废弃 f# 中的样板

发布于 2024-09-16 10:36:57 字数 192 浏览 11 评论 0原文

我使用了废弃你的样板并且Haskell 编程语言中的 Uniplate 库,我会发现基于可区分联合的泛型编程形式非常有用。 f# 编程语言中是否有等效的库?

I've used the Scrap Your Boilerplate and Uniplate libraries in the Haskell programming language, and I would find that form of generic programming over discriminated unions to be really useful. Is there an equivalent library in the f# programming language?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

水中月 2024-09-23 10:36:57

据我所知,没有;如果没有语言/编译器内置的支持,我希望唯一的选择是基于反射的版本。 (我不知道 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 所处理类型的每个节点,留下所有其他节点按原样。

Not that I know of; without support built-in to the language/compiler, I expect the only alternative is a reflection-based version. (I don't know how Uniplate is implemented - do you?)

Here's the code for a reflection-based version based on the example from the original presentation. I have not thought deeply about its limitations, but this was much simpler to write than I would have guessed.

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

The everywhere function traverses the entire structure of an arbitrary DU and applies the function f to each node that is the type that f works on, leaving all other nodes as-is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文