Recursion 递归判别并与映射

Recursion 递归判别并与映射,recursion,f#,functor,discriminated-union,Recursion,F#,Functor,Discriminated Union,我需要一种类型的树和这些树上的地图,所以我这样做: type 'a grouping = G of ('a * 'a grouping) list with member g.map f = let (G gs) = g gs |> List.map (fun (s, g) -> f s, g.map f) |> G 但这让我想知道: map成员是样板。在Haskell中,GHC将为我实现f

我需要一种类型的树和这些树上的地图,所以我这样做:

type 'a grouping = 
    G of ('a * 'a grouping) list
    with 
        member g.map f = 
            let (G gs) = g
            gs |> List.map (fun (s, g) -> f s, g.map f) |> G
但这让我想知道:

  • map
    成员是样板。在Haskell中,GHC将为我实现
    fmap
    …派生(函子)
    )。我知道F#没有类型类,但有没有其他方法可以避免我自己在F#中编写映射
  • 我能不能避开这行
    let(G gs)=G
  • 这整个结构是不是有点不习惯?对我来说这看起来很奇怪,但也许这只是因为将成员放在sum类型对我来说是新的
    我认为没有一种方法可以自动导出
    map
    ,但是有一种方法可以这样编写代码:

    #r @"FsControl.Core.dll"
    #r @"FSharpPlus.dll"
    
    open FSharpPlus
    open FsControl.Core.TypeMethods
    
    type 'a grouping = 
        G of ('a * 'a grouping) list
        with
            // Add an instance for Functor 
            static member instance (_:Functor.Map, G gs, _) = fun (f:'b->'c) -> 
                map (fun (s, g) -> f s, map f g) gs |> G
    
    // TEST
    let a = G [(1, G [2, G[]] )]
    let b = map ((+) 10) a        // G [(11, G [12, G[]] )]
    
    请注意,
    map
    确实超载了,您看到的第一个应用程序调用了
    List
    的实例。因此,它的行为类似于Haskell中的
    fmap

    还请注意,通过这种方式,您可以分解
    ggs
    ,而无需创建
    let(ggs)=G

    现在我想很多人都会同意你的解决方案更为实用,但对我来说,也应该开发新的习语,以获得更多的特征和克服目前的语言限制,这就是为什么我认为使用一个定义明确约定的库也是习惯用法的原因。
    无论如何,我同意@kvb的观点,因为将
    map
    定义到一个模块中稍微更为惯用,在该约定中也使用了,因此您有通用的
    map
    和特定的
    ModuleX.map

    我不认为有自动派生
    map
    的方法,但是有一种方法,您的代码可以这样编写:

    #r @"FsControl.Core.dll"
    #r @"FSharpPlus.dll"
    
    open FSharpPlus
    open FsControl.Core.TypeMethods
    
    type 'a grouping = 
        G of ('a * 'a grouping) list
        with
            // Add an instance for Functor 
            static member instance (_:Functor.Map, G gs, _) = fun (f:'b->'c) -> 
                map (fun (s, g) -> f s, map f g) gs |> G
    
    // TEST
    let a = G [(1, G [2, G[]] )]
    let b = map ((+) 10) a        // G [(11, G [12, G[]] )]
    
    请注意,
    map
    确实超载了,您看到的第一个应用程序调用了
    List
    的实例。因此,它的行为类似于Haskell中的
    fmap

    还请注意,通过这种方式,您可以分解
    ggs
    ,而无需创建
    let(ggs)=G

    现在我想很多人都会同意你的解决方案更为实用,但对我来说,也应该开发新的习语,以获得更多的特征和克服目前的语言限制,这就是为什么我认为使用一个定义明确约定的库也是习惯用法的原因。
    不管怎样,我同意@ KVB,在代码中定义<代码> MAP>代码>,在这个约定中也使用了,所以你有通用的<代码>地图>代码>和特定的<代码> MuleX。MAP< /COD> < /P>你考虑了一个让绑定函数<代码>让ReC映射f(G GS)=GS>List.map(Fun(s,g)-f s,map fg)|>G?是的。不过,我想避免这样做:使用
    member
    的好处似乎是,我避免了用名为
    mapG
    foldG
    之类的东西污染我的本地名称空间。而且我也不会让bind成为会员,对吧?@Sørendbois:这是最好的了。如果您尝试在F#中模拟Haskell,您的代码将比当前(直接的)解决方案复杂得多。@SørenDebois-将其作为
    分组
    模块中的let-bound定义可能更为惯用;然后,你可以打开模块,如果你要使用它很多,并使用<代码>地图<代码>以一种不合格的方式。你考虑了一个让绑定函数<代码>让ReC映射F(G GS)=GS>List.map(Fun(S,G)-F S,MAP FG)>G < /代码>?是的。不过,我想避免这样做:使用
    member
    的好处似乎是,我避免了用名为
    mapG
    foldG
    之类的东西污染我的本地名称空间。而且我也不会让bind成为会员,对吧?@Sørendbois:这是最好的了。如果您尝试在F#中模拟Haskell,您的代码将比当前(直接的)解决方案复杂得多。@SørenDebois-将其作为
    分组
    模块中的let-bound定义可能更为惯用;如果你打算大量使用这个模块,那么你可以打开它,并以一种非限定的方式使用
    map
    。很有趣。你能解释一下或者指出一个我可以去阅读
    实例(quot:Functor.Map,G gs,quot)
    )的地方吗?看看自述文件,我会对你的反馈感兴趣,所以请告诉我你是否认为我可以在解释中添加其他内容。很有趣。你能解释一下或者指出一个我可以去阅读
    实例(quo;Functor.Map,G gs,quo)
    的地方吗?请看一下位于的自述文件,我对你的反馈很感兴趣,所以请告诉我你是否认为我可以在解释中添加其他内容。