F#,使用map2和map3定义map4的简洁方法

标签 f#

这个问题仅是为了娱乐。请不要太在意这个问题。

我目前正在学习F#,并且我想看看是否存在使用现有函数List.map2,List.map3,管道向前/向后,向前/向后合成等来定义map4的简洁方法。

IE。

let map4 f a b c d = ......
map4 f [a1;a2] [b1;b2] [c1;c2] [d1;d2] 

// output: [f(a1,b1,c1,d1); f(a2,b2,c2,d2)]

我可以递归解决此问题,也可以定义一个新的运算符(请参见以下URL)

http://www.fssnip.net/9W/title/nary-Seqmap-

http://call-with-cc-en.blogspot.sg/2009/04/applicative-functors-mapping-function.html

我还可以通过使用部分应用的函数f(a,b,?,?)组合List.map2和List.map3来解决此问题
let map4 f a b c d =
    List.map3 (fun g y -> g y) (List.map2 f a b) c d

我可以尝试使用正向合成来缩短我的代码(并使其尽可能抽象/令人困惑)
let map4 f a =
    List.map2 f a >> List.map3 id;;

// Output type: f:('a -> 'b -> 'c -> 'd -> 'e) ->
// a:'a list -> ('b list -> 'c list -> 'd list -> 'e list)

我想知道是否可以通过摆脱“f”和“a”来进一步缩短它,从而导致:
let map4 = ...... (* Use only List.map2, List.map3, |>, |<, >>, <<, etc.*) ..........

这可能会使它不必要地令人困惑,但它会非常酷。谢谢你。

编辑:

适应TheInnerLight的答案:
let inline (<!>) f xList = List.map f xList

let inline (<*>) gList xList = List.map2 (id) gList xList

let map4 f w x y z = f <!> w <*> x <*> y <*> z
let map5 f v w x y z = f <!> v <*> w <*> x <*> y <*> z
let map6 f u v w x y z = f <!> u <*> v <*> w <*> x <*> y <*> z

最佳答案

这是应用程序编程风格(即applicative functors)的良好用法。

只需定义apply函数和一些辅助运算符即可:

module List =
    // val apply : f:('a -> 'b) list -> x:'a list -> 'b list
    let apply f x = List.map2 (fun f x -> f x) f x

    // val inline ( <!> ) : f:('a -> 'b) -> x:'a list -> 'b list
    let inline (<!>) f x = List.map f x

    // val inline ( <*> ) : f:('a -> 'b) list -> x:'a list -> 'b list
    let inline (<*>) f x = apply f x

然后使用map并应用以定义mapN函数。
    // val map2 : f:('a -> 'b -> 'c) -> x:'a list -> y:'b list -> 'c list
    let map2 f x y = f <!> x <*> y

    // val map3 : f:('a -> 'b -> 'c -> 'd) -> x:'a list -> y:'b list -> z:'c list -> 'd list
    let map3 f x y z = f <!> x <*> y <*> z

    // val map4 : f:('a -> 'b -> 'c -> 'd -> 'e) -> x:'a list -> y:'b list -> z:'c list -> a:'d list -> 'e list
    let map4 f x y z a = f <!> x <*> y <*> z <*> a

    // val map8 : f:('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h -> 'i) -> x:'a list -> y:'b list -> z:'c list -> a:'d list -> b:'e list -> c:'f list -> d:'g list -> e:'h list -> 'i list
    let map8 f x y z a b c d e = f <!> x <*> y <*> z <*> a <*> b <*> c <*> d <*> e

如您所见,您可以继续添加参数以定义心脏内容的任意mapN

由于该问题专门询问有关使用map2map3的问题,因此您可以以相同的样式执行此操作,尽管它不太简洁,例如:
    let map4_2 f x y z a = List.map2 f x y <*> z <*> a

    let map4_3 f x y z a = List.map3 f x y z <*> a

希望你能明白。

顺便说一句,我认为值得一提的是任何monad都会自动成为可应用的仿函数,因此可以使用此模式使用多种类型,这里有一个Async示例。
module Async = 
    // val map : f:('a -> 'b) -> x:Async<'a> -> Async<'b>
    let map f x = async.Bind(x, async.Return << f)

    // val apply : f:Async<('a -> 'b)> -> x:Async<'a> -> Async<'b>
    let apply f x = async.Bind(f, fun fe -> map fe x)

    // val inline ( <!> ) : f:('a -> 'b) -> x:Async<'a> -> Async<'b>
    let inline (<!>) f x = map f x

    // val inline ( <*> ) : f:Async<('a -> 'b)> -> x:Async<'a> -> Async<'b>
    let inline (<*>) f x = apply f x

    // val map4 : f:('a -> 'b -> 'c -> 'd -> 'e) -> x:Async<'a> -> y:Async<'b> -> z:Async<'c> -> a:Async<'d> -> Async<'e>
    let map4 f x y z a = f <!> x <*> y <*> z <*> a

关于F#,使用map2和map3定义map4的简洁方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42901373/

相关文章:

f# - 如何使数组洗牌函数在后续调用中产生不同的结果

f# - 与 fsharp 中的 typeof 匹配

F# 中的异步 EF 查询

arrays - F#:为什么 Array.createZero 这么快?

http - 在 Suave 应用程序中上传文件

f# - 如何使用 F# 在 Akka.Remote 中发送带有元组的消息?

list - 从F#中的列表中切片类似的功能

f# - 如何在 F# 中将两个(双选项)相乘

f# - 运行使用 FSharp.Data 的单元测试时出现 MissingMethodException

c# - 用于演示项目的 .NET 托管