Haskell:我如何“向后”编写函数,例如Clojure的线程(->)?

问题描述 投票:1回答:2

这里是Haskell的新手。

我想写:

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

reversed,例如此伪代码:

[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()等的流畅接口/链接模式。

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

haskell clojure functional-programming function-composition
2个回答
4
投票

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

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

如果您确实不喜欢导入该模块,则定义就是(&) = flip ($)


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.