Answers:
我有点投机...
文化:我认为|>是F#“文化”中的重要运算符,也许与.Haskell 类似。F#具有函数组合运算符,<<但我认为F#社区倾向于使用无点样式而不是Haskell社区。
语言差异:我对两种语言的了解还不够,但是也许使let-bindings泛化的规则足以影响这一点。例如,我知道在F#中有时会写
let f = exp
将不会编译,并且您需要显式的eta转换:
let f x = (exp) x // or x |> exp
使其编译。这也使人们远离无分/组合风格,而转向流水线风格。另外,F#类型推断有时需要进行流水线处理,以便在左侧显示一个已知类型(请参见此处)。
(就我个人而言,我发现无分的样式不可读,但我想所有新事物/不同事物在您习惯之前似乎都是不可读的。)
我认为这两种语言在两种语言中都可能可行,历史/文化/事故可能会定义为什么每个社区都定居于不同的“吸引人”。
.和$,因此人们继续使用它们。
(|>)由于从左到右的类型检查,在F#中很重要。例如:
List.map (fun x -> x.Value) xs
通常不会进行类型检查,因为即使的类型xs已知,类型检查器x看到的时候lambda 参数的类型也不知道,因此它不知道如何解析x.Value。
相反
xs |> List.map (fun x -> x.Value)
会正常工作,因为的类型xs会导致x已知。
由于像这样的结构涉及名称解析,因此需要从左到右的类型检查x.Value。西蒙·佩顿·琼斯(Simon Peyton Jones)提出了为Haskell添加类似类型的名称解析的建议,但他建议使用局部约束来跟踪类型是否支持特定操作。因此,在第一个样本中,x需要保留某个Value属性的要求,直到xs被发现为止,并且可以解决该要求。但是,这确实使类型系统复杂化。
更多猜测,这次是从主要的Haskell方面开始的...
($) 是翻转 (|>),当您无法编写无点代码时,它的用法很常见。因此,(|>)在Haskell 中不使用的主要原因是它的位置已经被($)。
此外,从F#的一些经验来看,我认为(|>)它在F#代码中非常受欢迎,因为它类似于Subject.Verb(Object) OO结构。由于F#旨在实现平滑的功能/ OO集成,Subject |> Verb Object因此对于新功能程序员而言,这是一个相当平滑的过渡。
就个人而言,我也喜欢从左至右思考,因此我(|>)在Haskell中使用,但我认为没有其他人这样做。
Data.Sequence.|>,但是$>看起来很合理,可以避免在那里发生冲突。老实说,只有那么多漂亮的运算符,所以我将|>同时使用这两种运算符,并逐案处理冲突。(而且,我也很想将别名Data.Sequence.|>化为snoc)
($)并且(|>)不是应用程序组成。两者是相关的(如问题注释所示),但它们是不相同的(您fc是(Control.Arrow.>>>)针对函数的)。
|>实际上|比其他任何东西更能使我想起UNIX 。
|>F#的另一个好处是它具有Visual Studio中IntelliSense的出色属性。键入|>,您会获得一个可以应用于左侧值的函数列表,类似于.在对象后键入时发生的情况。
我认为我们很困惑。Haskell的(.)等同于F#的(>>)。不要与F#(|>)混淆,F#只是反向函数应用程序,就像Haskell的($)-反向:
let (>>) f g x = g (f x)
let (|>) x f = f x
我相信Haskell程序员确实$经常使用。也许不像F#程序员倾向于使用的那样频繁|>。另一方面,一些F#家伙使用>>程度却很可笑:http : //blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx
$运算符-反转了一样,您也可以轻松地将其定义为:a |> b = flip ($)它等同于F#的管道,例如,您可以这样做[1..10] |> map f
.)与()相同<<,而(>>)是相反的组成。那就是( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3vs( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
.等于>>。我不知道F#是否具有,<<但是那是等效的(例如Elm)。
如果要|>在Haskell中使用F#,则在Data.Function中是&运算符(因为base 4.8.0.0)。
&了|>?我觉得|>它更加直观,这也让我想起了Unix管道运算符。
有些人在Haskell中也使用从左到右(消息传递)样式。见,例如,MPS上Hackage库。一个例子:
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]
有一个很好的理由有时会偏爱从左到右的构图:评估顺序遵循阅读顺序。
我认为F#的管道前移运算符(|>)应该与haskell中的(&)对决。
// pipe operator example in haskell
factorial :: (Eq a, Num a) => a -> a
factorial x =
case x of
1 -> 1
_ -> x * factorial (x-1)
// terminal
ghic >> 5 & factorial & show
如果您不喜欢(&)运算符,则可以像F#或Elixir一样自定义它:
(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 1 |>
ghci>> 5 |> factorial |> show
为什么infixl 1 |>呢 请参阅数据功能(&)中的文档
infixl =中缀+左联想
infixr =中缀+右关联
(.)表示功能组成。在数学中表示(fg)(x)= f(g(x))。
foo = negate . (*3)
// ouput -3
ghci>> foo 1
// ouput -15
ghci>> foo 5
它等于
// (1)
foo x = negate (x * 3)
要么
// (2)
foo x = negate $ x * 3
($)运算符也在Data-Function($)中定义。
(.)用于创建Hight Order Function或closure in js。参见示例:
// (1) use lamda expression to create a Hight Order Function
ghci> map (\x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]
[-5,-3,-6,-7,-3,-2,-19,-24]
// (2) use . operator to create a Hight Order Function
ghci> map (negate . abs) [5,-3,-6,7,-3,2,-19,24]
[-5,-3,-6,-7,-3,-2,-19,-24]
哇,更少(代码)更好。
|>并.ghci> 5 |> factorial |> show
// equals
ghci> (show . factorial) 5
// equals
ghci> show . factorial $ 5
left —> right和之间是不同的right —> left。⊙﹏⊙|||
|>并且&比.
因为
ghci> sum (replicate 5 (max 6.7 8.9))
// equals
ghci> 8.9 & max 6.7 & replicate 5 & sum
// equals
ghci> 8.9 |> max 6.7 |> replicate 5 |> sum
// equals
ghci> (sum . replicate 5 . max 6.7) 8.9
// equals
ghci> sum . replicate 5 . max 6.7 $ 8.9
IT支持 :
&是Haskell的|>。深埋在这个线程中,花了我几天时间才发现。我经常使用它,因为您自然会从左到右阅读以遵循您的代码。