Haskell:如何像 Clojure 的线程 (->) 那样组合函数 "backwards"?

Haskell: How do I compose functions "backwards", like Clojure's thread (->)?

这里是 Haskell 的新手。

我想写:

take 1 $ take 2 [1, 2, 3] -- = 1

反转,像这样的伪代码:

[1, 2, 3] -> take 2 -> take 1 -- = 1

在 Clojure 中,我们可以这样做:

(->> [1 2 3]
  (take 2)
  (take 1)) ;=> (1)

Clojure 这样做是因为 ->> 是一个将表达式重写为 (take 1 (take 2 [1 2 3])) 的宏,但是因为 Haskell 是惰性的并且有部分等等,所以看起来应该很容易.

我想这样做是因为先获取数据然后读取函数以执行它们是一种阅读代码的好方法。我被 Clojure 宠坏了!

它类似于面向对象语言中var.action1().action2()等的流畅接口/链模式。

我想这在模板 Haskell 中是可能的,但肯定有一种我还不知道的内置方法可以做到这一点?谢谢!

(&),您需要从Data.Function导入。

> import Data.Function
> [1,2,3] & take 2 & take 1
[1]

如果你真的厌恶导入那个模块,定义就是 (&) = flip ($).

chepner 的回答完全正确。

还有更多滥用 Haskell 语法的技巧,但下面的代码 不应 用于任何严肃的应用程序。

RebindableSyntax 打破了用户对标准结构含义的期望。可变参数函数具有糟糕的类型推断、错误报告和极端情况(这些问题可以通过不合理的努力来缓解,但从未完全解决)。

可重新绑定的语法

符号 do {x ; y}x >> y 的糖分,RebindableSyntax 扩展允许您重新绑定 (>>)。您可以将其重新定义为(反向)函数组合,例如:

y :: [Int]
y = [1,2,3] & do
  take 2
  take 1
 where
  (>>) = flip (.)

变量

您可以使用类型 类 将 (->>) 定义为可变参数函数。

z :: [Int]
z = (->>) [1,2,3]
  (take 2)
  (take 1)

class App a b where
  (->>) :: a -> b

instance (a ~ a', App b c) => App a ((a' -> b) -> c) where
  (->>) x y = (->>) (y x)

instance {-# OVERLAPPABLE #-} (a ~ a') => App a a' where
  (->>) = id

完整要点:https://gist.github.com/Lysxia/3461f489cc5057ea089e23a4eede375a