我需要一种树和一张地图,所以我这样做:
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
(... deriving (Functor)
)。我知道F#没有类型类,但还有其他方法可以避免在F#中自己编写地图吗?let (G gs) = g
?答案 0 :(得分:4)
我认为有一种方法可以自动导出map
,但是有emulate type classes in F#的方式,您的代码可以像这样编写:
#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
确实已超载,您看到的第一个应用程序调用{{1}}的实例,第二个应用程序调用{{1}}的实例。因此它在Haskell中的行为类似于List<'a>
。
另请注意,您可以在不创建grouping<'a>
fmap
现在关于什么是惯用的,我想很多人会同意你的解决方案更像F#惯用,但对我来说,也应该开发新的习语,以获得更多的功能并克服当前的语言限制,这就是我考虑的原因使用定义明确惯例的库也是惯用的。
无论如何,我同意@kvb,因为将G gs
定义到一个模块中稍微更惯用,在F#+中也使用了约定,所以你有通用的{{1}和特定的let (G gs) = g