Haskell:我如何“向后”组合函数,比如 Clojure 的线程 (->)?

0at*_*man 1 haskell functional-programming clojure function-composition

这里是 Haskell 的新手。

我想写:

take 1 $ take 2 [1, 2, 3] -- = 1
Run Code Online (Sandbox Code Playgroud)

reversed,就像这个伪代码:

[1, 2, 3] -> take 2 -> take 1 -- = 1
Run Code Online (Sandbox Code Playgroud)

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

(->> [1 2 3]
  (take 2)
  (take 1)) ;=> (1)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

che*_*ner 11

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

> import Data.Function
> [1,2,3] & take 2 & take 1
[1]
Run Code Online (Sandbox Code Playgroud)

如果您真的不喜欢导入该模块,那么定义很简单(&) = flip ($)

  • `&` *不是*组合运算符;它是一个应用程序运营商。`Control.Arrow` 提供 `(>>>) = Flip (.)`,所以你可以写 `[1,2,3] & (take 2 >>> take 1)` (括号是必需的,因为 `& ` 和 `>>>` 具有相同的优先级但不同的关联性) (4认同)

Li-*_*Xia 5

切普纳的答案是完全正确的。

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

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

可重新绑定语法

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

y :: [Int]
y = [1,2,3] & do
  take 2
  take 1
 where
  (>>) = flip (.)
Run Code Online (Sandbox Code Playgroud)

变量

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

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
Run Code Online (Sandbox Code Playgroud)

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