【发布时间】:2013-02-07 18:47:27
【问题描述】:
我知道(||>) 是(a' * 'b) -> ('a -> b' -> 'c) -> 'c
但我一直觉得这很有用,我想知道我是不是在重新发明轮子:
// ('a * 'a) -> ('a -> 'b) -> ('b * 'b)
let inline (|>>) (a,b) f = (f a, f b)
(*有可能,我半小时前才发现ceil函数!)
【问题讨论】:
我知道(||>) 是(a' * 'b) -> ('a -> b' -> 'c) -> 'c
但我一直觉得这很有用,我想知道我是不是在重新发明轮子:
// ('a * 'a) -> ('a -> 'b) -> ('b * 'b)
let inline (|>>) (a,b) f = (f a, f b)
(*有可能,我半小时前才发现ceil函数!)
【问题讨论】:
不,它没有。
但是,如果您使用 FParsec,您会经常遇到它的变体。这是 FParsec 文档中的类型签名:
val (|>>): Parser<'a,'u> -> ('a -> 'b) -> Parser<'b,'u>
我认为该库有一组设计精良的运算符,它们也可以泛化用于其他目的。 FParsec 运算符列表可以在here 找到。
我做了一点挖掘; |>> 运算符似乎没有 built-in Haskell counterpart,尽管使用 Control.Arrow 很容易定义。
【讨论】:
您描述的运算符本质上是用于二元素元组的map 函数。 map 函数通常有一个签名(对于某些 F<'a> 可能是 seq<'a> 或 F# 库中的许多其他类型):
map : ('a -> 'b) -> F<'a> -> F<'b>
所以,如果您将F<'a> 定义为一个二元组,那么您的函数实际上就是map(如果您翻转参数):
type F<'a> = 'a * 'a
let map f (a, b) = (f a, f b)
该操作在 F# 库的任何地方都没有内置,但意识到它实际上匹配在其他地方的 F# 库(列表、序列、数组等)中非常常见的模式是很有用的
查看@pad 引用的 Haskell 答案 - 原则上,Haskell 可以使用 type classes 为支持此类操作的所有类型定义相同的函数(因此您只需编写 @987654329 @ 而不是 Seq.map 或而不是你的 TwoElementTuple.map,但由于各种技术原因它实际上不起作用 - 所以 Haskellers 需要以不同的方式称呼它)。
在 F# 中,为不同类型定义单个 map 函数并不容易,但您仍然可以将您的函数视为用于二元素元组的 map(即使您发现它更容易给出它是一个符号运算符名称,而不是名称 map。)
【讨论】:
map...但我必须承认我喜欢管道语义..