War es hilfreich?

Lösung

Nicht, dass ich kenne; ohne Unterstützung eingebaut, um die Sprache / Compiler erwarte ich, dass die einzige Alternative ein Spiegelbild-basierte Version ist. (Ich weiß nicht, wie Uniplate implementiert - tun Sie)

Hier ist der Code für eine Reflexion-basierte Version auf dem Beispiel aus der ursprünglichen Präsentation basiert. Ich habe nicht daran gedacht, tief über seine Grenzen, aber das war viel einfacher zu schreiben, als ich geahnt hätte.

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

Die everywhere Funktion durchläuft die gesamte Struktur eines beliebig ICH und wendet die Funktion f an jeden Knoten, der der Typ ist, dass f arbeitet, wird alle anderen Knoten zu verlassen, wie sie ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top