Rottami tuo Boilerplate in F #
-
02-10-2019 - |
Domanda
Ho usato il Scrap tuo Boilerplate e librerie UniPlate nella Haskell linguaggio di programmazione, e vorrei trovare quella forma di programmazione generico su unioni discriminati per essere veramente utile. C'è una libreria equivalente nel linguaggio di programmazione F #?
Soluzione
Non che io sappia; senza supporto built-in per la lingua / compilatore, mi aspetto che l'unica alternativa è una versione riflessione-based. (Non so come UniPlate è implementato -? Ti)
Ecco il codice per una versione riflessione basata sull'esempio dalla presentazione originale. Non ho pensato profondamente a cuore i suoi limiti, ma questo era molto più semplice da scrivere di quanto avrei immaginato.
type Company = C of Dept list
and Dept = D of Name * Manager * SubUnit list
and SubUnit = | PU of Employee | DU of Dept
and Employee = E of Person * Salary
and Person = P of Name * Address
and Salary = S of float
and Manager = Employee
and Name = string
and Address = string
let data = C [D("Research",E(P("Fred","123 Rose"),S 10.0),
[PU(E(P("Bill","15 Oak"),S 5.0))])]
printfn "%A" data
open Microsoft.FSharp.Reflection
let everywhere<'a,'b>(f:'a->'a, src:'b) = // '
let ft = typeof<'a> // '
let rec traverse (o:obj) =
let ot = o.GetType()
if ft = ot then
f (o :?> 'a) |> box // '
elif FSharpType.IsUnion(ot) then
let info,vals = FSharpValue.GetUnionFields(o, ot)
FSharpValue.MakeUnion(info, vals |> Array.map traverse)
else
o
traverse src :?> 'b // '
let incS (S x) = S(x+1.0)
let newData = everywhere(incS, data)
printfn "%A" newData
La funzione everywhere
attraversa l'intera struttura di un DU arbitraria e applica la funzione f
a ciascun nodo che è il tipo che f
funziona su, lasciando tutti gli altri nodi così com'è.