Я не думаю, что есть способ автоматического получения map
, однако есть способ эмулировать классы типов в 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
действительно перегружен, первое приложение, которое вы видите, вызывает экземпляр для List<'a>
, а второе — экземпляр для grouping<'a>
. Так что он ведет себя как fmap
в Haskell.
Также обратите внимание, что таким образом вы можете разложить G gs
без создания let (G gs) = g
Теперь, что касается идиоматичности, я думаю, многие люди согласятся, что ваше решение более идиоматично для F#, но для меня также должны быть разработаны новые идиомы, чтобы получить больше возможностей и преодолеть текущие языковые ограничения, поэтому я рассматриваю возможность использования библиотеки, которая определяет четкие соглашения. также идиоматический.
В любом случае, я согласен с @kvb в том, что определение map
в модуле в F#+ несколько более идиоматично. это соглашение также используется, поэтому у вас есть общий map
и конкретный ModuleX.map
person
Gus
schedule
26.03.2014
let rec map f (G gs) = gs |> List.map (fun (s, g) -> f s, map f g) |> G
? - person kaefer   schedule 26.03.2014member
заключается в том, что я избегаю загрязнения своего локального пространства имен вещами с именамиmapG
иfoldG
и т.п. И я не могу позволить связать член, верно? - person Søren Debois   schedule 26.03.2014Grouping
; тогда вы можете просто открыть модуль, если собираетесь его часто использовать, и использоватьmap
безоговорочно. - person kvb   schedule 26.03.2014