Haskell组成(。)与F#的pipe道转发运算符(|>)
在F#中,使用pipe道转发运算符|>
很常见。 然而,在Haskell中,我只见过函数组合(.)
被使用。 我明白,他们是相关的 ,但有没有一个语言的原因,没有在Haskell中使用pipe道转发还是别的东西?
我有点投机…
文化 :我认为|>
是F#”文化“中的一个重要的运营者,也许与之类似.
为Haskell。 F#有一个函数组合运算符<<
但我认为F#社区倾向于使用比Haskell社区更less的无点风格 。
语言差异 :我不太了解两种语言进行比较,但是可能有关将let-bindings一般化的规则有很大的不同,以至于影响这一点。 例如,我知道在F#有时写作
let f = exp
不会编译,你需要明确的eta转换:
let fx = (exp) x // or x |> exp
使其编译。 这也使得人们远离无点/构图风格,转向stream水线风格。 而且,F#types推理有时需要stream水线操作,以便在左侧出现一个已知types(请参见此处 )。
(就个人而言,我觉得无分的风格是不可读的,但是我认为每个新的/不同的东西在你习惯之前似乎是不可读的。)
我认为两种语言都可能是可行的,历史/文化/意外可能会解释为什么每个社区都有不同的“吸引力”。
在F# (|>)
很重要,因为从左到右的types检查。 例如:
List.map (fun x -> x.Value) xs
一般不会检查,因为即使xs
的types是已知的, x.Value
的参数x
的types在typechecker看到它的时候是不知道的,所以它不知道如何parsingx.Value
。
相反
xs |> List.map (fun x -> x.Value)
将会正常工作,因为xs
的types将导致x
的types被知道。
由于涉及像x.Value
这样的结构的名称parsing,所以需要x.Value
。 西蒙·佩顿·琼斯(Simon Peyton Jones)已经写了一个向Haskell添加类似名称parsing的build议,但是他build议使用局部约束来跟踪一个types是否支持特定的操作。 因此,在第一个示例中, x
需要一个Value
属性的要求会一直持续到xs
被发现,这个需求可以被解决。 不过这确实使types系统复杂化了。
更多的猜测,这次从主要的Haskell方面… …
($)
是(|>)
的翻转,当你不能写无点代码时,它的使用是相当普遍的。 所以(|>)
在Haskell中没有使用的主要原因是它的位置已经被($)
占用了。
另外,从F#的经验来看,我认为(|>)
在F#代码中非常stream行,因为它类似于OO的Subject.Verb(Object)
结构。 由于F#旨在实现平滑的function/ OO集成,因此Subject |> Verb Object
对新function程序员来说是一个非常平滑的过渡。
就我个人而言,我也喜欢从左到右思考,所以我在Haskell中使用(|>)
,但是我不认为其他人会这么做。
我认为我们混淆的东西。 Haskell的( .
)等价于F#( >>
)。 不要和F#的( |>
)混淆,它只是反函数应用,就像Haskell的( $
) – 颠倒过来:
let (>>) fgx = g (fx) let (|>) xf = fx
我相信Haskell程序员经常使用$
。 也许不像F#程序员倾向于使用|>
那样频繁。 另一方面,一些F#的人使用>>
到一个荒谬的程度: http : //blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx
Haskell中的从左到右的组合
有些人也在Haskell中使用从左到右(消息传递)的风格。 例如,见Hackage上的mps库。 一个例子:
euler_1 = ( [3,6..999] ++ [5,10..999] ).unique.sum
我认为这种风格在某些情况下看起来不错,但是很难阅读(需要知道库和它的所有操作符,重新定义的(.)
也是令人不安的)。
Control.Category中也有从左到右以及从右到左的合成运算符,它是基本包的一部分。 分别比较>>>
和<<<
:
ghci> :m + Control.Category ghci> let f = (+2) ; g = (*3) in map ($1) [f >>> g, f <<< g] [9,5]
有时有一个很好的理由喜欢从左到右的作文:评价顺序遵循阅读顺序。
我已经看到>>>
被用于flip (.)
,我经常使用它自己,特别是从最左侧到右侧最好理解的长链。
>>>
实际上来自Control.Arrow,并且不仅仅是函数。
如果你想在Haskell中使用F#的|>
,那么在Data.Function中就是&
运算符(从base 4.8.0.0
)。
除了风格和文化,这可以归结为优化纯代码或不纯代码的语言devise。
|>
操作符在F#中很常见,因为它有助于隐藏两个主要不纯代码出现的限制:
- 从左到右的types推断,没有结构性的子types。
- 价值限制。
注意前面的限制在OCaml中是不存在的,因为子types是结构化的而不是名义的,所以结构types可以通过types推断进行统一而容易地提炼出来。
Haskell采取了不同的权衡,select专注于主要的纯代码,这些限制可以被解除。
这是我第一次尝试Haskell(在Rust和F#之后),并且我能够定义F#的操作符:
(|>) :: a -> (a -> b) -> b (|>) xf = fx infixl 0 |>
它似乎工作:
factorial x = case x of 1 -> 1 _ -> x * factorial (x-1) main = 5 |> factorial |> print
我敢打赌,一个Haskell专家可以给你一个更好的解决scheme。