在 F# 中,使用管道转发运算符|>
, 是很常见的。但是,在 Haskell 中,我只见过函数组合(.)
, 被使用。我知道它们是相关的,但是在 Haskell 中没有使用管道转发是否有语言原因,还是其他原因?
10 回答
在 F#(|>)
中很重要,因为从左到右的类型检查。例如:
List.map (fun x -> x.Value) xs
通常不会进行类型检查,因为即使类型xs
已知,lambda 参数的类型在类型检查x
器看到它时也是未知的,因此它不知道如何解析x.Value
.
相比之下
xs |> List.map (fun x -> x.Value)
会正常工作,因为类型xs
会导致x
已知类型。
由于像x.Value
. Simon Peyton Jones 写了一个提议,为 Haskell 添加类似的名称解析,但他建议使用局部约束来跟踪类型是否支持特定操作。因此,在第一个示例中,x
需要Value
属性的需求将被结转,直到xs
看到并且可以解决此需求。不过,这确实使类型系统复杂化。
我有点投机...
Culture:我认为|>
是 F#“文化”中的一个重要运算符,.
对于 Haskell 来说可能也是如此。F# 有一个函数组合运算符,但我认为 F# 社区比 Haskell 社区更<<
倾向于使用无点样式。
语言差异:我对这两种语言的了解不够多,无法比较,但也许泛化 let-bindings 的规则差异很大,足以影响这一点。例如,我知道在 F# 中有时会写
let f = exp
不会编译,你需要明确的 eta 转换:
let f x = (exp) x // or x |> exp
使其编译。这也引导人们远离无点/组合风格,而转向流水线风格。此外,F# 类型推断有时需要流水线,因此已知类型出现在左侧(请参阅此处)。
(就我个人而言,我发现无积分风格不可读,但我想每一个新的/不同的东西在你习惯之前似乎都是不可读的。)
我认为这两种语言都可能是可行的,历史/文化/事故可能会定义为什么每个社区都选择不同的“吸引者”。
更多的猜测,这一次主要来自 Haskell 方面......
($)
是 的翻转(|>)
,当您无法编写无点代码时,它的使用非常普遍。所以在 Haskell 中没有使用的主要原因(|>)
是它的位置已经被($)
.
另外,从一点 F# 的经验来讲,我认为(|>)
在 F# 代码中如此流行是因为它类似于Subject.Verb(Object)
OO 的结构。由于 F# 旨在实现平滑的函数式/OO 集成,Subject |> Verb Object
因此对于新的函数式程序员来说是一个非常平滑的过渡。
就个人而言,我也喜欢从左到右思考,所以我(|>)
在 Haskell 中使用,但我认为其他人不会这样做。
我认为我们把事情搞糊涂了。Haskell 的 ( .
) 等价于 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
如果您想|>
在 Haskell 中使用 F#,那么在Data.Function中是&
运算符(因为base 4.8.0.0
)。
我已经看到>>>
被用于flip (.)
,而且我自己也经常使用它,尤其是对于从左到右最容易理解的长链。
>>>
实际上来自 Control.Arrow,并且不仅仅适用于功能。
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]
有时更喜欢从左到右的构图是有充分理由的:评估顺序遵循阅读顺序。
除了风格和文化之外,这归结为优化纯代码或不纯代码的语言设计。
该|>
运算符在 F# 中很常见,主要是因为它有助于隐藏两个主要出现在不纯代码中的限制:
- 没有结构子类型的从左到右类型推断。
- 值限制。
请注意,OCaml 中不存在前一个限制,因为子类型是结构的而不是名义的,因此随着类型推断的进行,结构类型很容易通过统一进行细化。
Haskell 采取了不同的权衡,选择专注于可以解除这些限制的主要纯代码。
我认为 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 |>
?请参阅Data-Function (&)中的文档
中缀 = 中缀 + 左结合性
中缀 = 中缀 + 右结合性
(.)
( .
) 表示功能组合。这意味着(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支持 :
- Java:RxJava
- JavaScript:RxJS
- C#:Rx.NET
- C#(统一):UniRx
- 斯卡拉:RxScala
- Clojure:RxClojure
- C++:RxCpp
- Lua:RxLua
- 红宝石:Rx.rb
- 蟒蛇:RxPY
- 去:RxGo
- Groovy:RxGroovy
- JRuby:RxJRuby
- Kotlin:RxKotlin
- 斯威夫特:RxSwift
- PHP:RxPHP
- 灵药:reaxive
- 飞镖:RxDart
这是我尝试 Haskell 的第一天(在 Rust 和 F# 之后),我能够定义 F# 的 |> 运算符:
(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 0 |>
它似乎有效:
factorial x =
case x of
1 -> 1
_ -> x * factorial (x-1)
main =
5 |> factorial |> print
我敢打赌,Haskell 专家可以为您提供更好的解决方案。