2010-08-29 12 views

Respuesta

11

No es que yo sepa; sin compatibilidad incorporada al lenguaje/compilador, espero que la única alternativa sea una versión basada en la reflexión. (No sé cómo se implementa Uniplate, ¿verdad?)

Aquí está el código de una versión basada en la reflexión basada en el ejemplo de la presentación original. No he pensado profundamente acerca de sus limitaciones, pero esto fue mucho más simple de lo que hubiera imaginado.

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 función everywhere atraviesa toda la estructura de un DU arbitraria y aplica la función f a cada nodo que es el tipo que f funciona en, dejando todos los demás nodos como está.

+0

Esta es una buena sugerencia, tendré que pensar en las implicaciones de rendimiento de tal enfoque. Probablemente no importe para mi uso particular en cualquier caso. –

+0

re: su pregunta sobre cómo se implementa Uniplate, la fuente está disponible en http://community.haskell.org/~ndm/darcs/uniplate/. –

+0

He aceptado su respuesta ya que creo que es un buen enfoque, pero hago un cambio para que funcione correctamente: Reemplacé 'ft = ot' con 'ot.IsSubclassOf (ft)' - de lo contrario no coincide cuando el tipo de argumento de f, es decir, 'a es más genérico que el argumento específico que se pasa. –