Ho usato le librerie Scrap Your Boilerplate e Uniplate nel linguaggio di programmazione Haskell e troverei davvero utile quella forma di programmazione generica su unioni discriminate. Esiste una libreria equivalente nel linguaggio di programmazione f #?Scrap Your Boilerplate in f #
11
A
risposta
11
Non che io sappia; senza supporto integrato nel linguaggio/compilatore, mi aspetto che l'unica alternativa sia una versione basata su reflection. (Non so come sia implementato lo Uniplate, vero?
Ecco il codice per una versione basata su riflessione basata sull'esempio della presentazione originale. Non ho pensato profondamente ai suoi limiti, ma era molto più semplice 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, lasciando tutti gli altri nodi così com'è.
Questo è un buon suggerimento, dovrò pensare alle implicazioni delle prestazioni di un tale approccio. In ogni caso, probabilmente non ha importanza per il mio caso particolare. –
re: la tua domanda su come implementare Uniplate la fonte è disponibile su http://community.haskell.org/~ndm/darcs/uniplate/. –
Ho accettato la tua risposta poiché ritengo sia un buon approccio, ma apporto una modifica per farlo funzionare correttamente: Ho sostituito "ft = ot" con "ot.IsSubclassOf (ft)" - altrimenti non riesce a corrispondere quando il tipo di argomento di f, cioè 'a è più generico rispetto all'argomento specifico che viene passato. –