Избавьтесь от своего шаблона в f #

Я воспользовался Утилизировать шаблон и Библиотеки Uniplate на языке программирования Haskell, и я считаю, что эта форма универсального программирования поверх размеченных объединений действительно полезна. Есть ли эквивалентная библиотека на языке программирования f#?


person Richard Warburton    schedule 29.08.2010    source источник


Ответы (1)


Не то, что я знаю из; без поддержки, встроенной в язык/компилятор, я ожидаю, что единственной альтернативой является версия, основанная на отражении. (Я не знаю, как реализован Uniplate, а вы?)

Вот код для версии, основанной на отражении, на основе примера из оригинальной презентации. Я не задумывался глубоко о его ограничениях, но написать это было гораздо проще, чем я мог предположить.

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

Функция everywhere просматривает всю структуру произвольного DU и применяет функцию f к каждому узлу того типа, с которым работает f, оставляя все остальные узлы как есть.

person Brian    schedule 29.08.2010
comment
Это хорошее предложение, мне придется подумать о последствиях такого подхода для производительности. В любом случае, это, вероятно, не имеет значения для моего конкретного случая использования. - person Richard Warburton; 30.08.2010
comment
Re: ваш вопрос о том, как реализован Uniplate, исходный код доступен по адресу community.haskell.org/ ~ndm/darcs/uniplate . - person Richard Warburton; 30.08.2010
comment
Я принял ваш ответ, так как считаю его хорошим подходом, но я вношу изменения, чтобы заставить его работать правильно: я заменил «ft = ot» на «ot.IsSubclassOf (ft)» — иначе он не соответствует когда тип аргумента f, т.е. 'a, является более общим, чем передаваемый конкретный аргумент. - person Richard Warburton; 30.08.2010
comment
В первом приближении Uniplate реализован с помощью магии. :] Тем не менее, Uniplate, SYB и связанные с ними библиотеки в основном существуют как структурированные, явные реализации того, что делает отражение. В Haskell не требуется специальной поддержки (автоматическая генерация экземпляров — это просто удобство), но я не знаю, существуют ли используемые методы в F#, и в любом случае я ожидаю, что было бы более разумно просто строить поверх существующие объекты для размышлений, как в вашем примере здесь. - person C. A. McCann; 16.06.2011
comment
См. также social.msdn. microsoft.com/Forums/en-US/fsharpgeneral/thread/ - person Brian; 01.12.2011