Python:类似Haskell./ $

Dan*_*uck 4 python haskell functional-programming combinators

在Haskell中,我会写:

main = do mapM_ print . map (\x -> x^2) . filter (\x -> (mod x 2) == 0) $ [1..20]
Run Code Online (Sandbox Code Playgroud)

在Python我将不得不为使用许多括号或无用的变量...有像什么.,并$在Python?

Cor*_*mer 6

(我不熟悉Haskell,但如果我正确理解你的代码片段......)

您可以使用列表推导来执行过滤和取幂.

[i**2 for i in range(1,21) if i%2 == 0]
Run Code Online (Sandbox Code Playgroud)

  • 你也可以通过调整范围来删除`if`后卫:`range(2,21,2)`. (5认同)

Eri*_*lun 5

我会使用任何可用的惯用 Python 工具,例如列表推导式,正如其他人指出的那样,而不是试图假装您正在编写 Haskell,但如果您真的必须,您compose甚至可以在 Python 中使用组合器函数:

# this is essentially just foldr (or right `reduce`) specialised on `compose2`
def compose(*args):
    ret = identity
    for f in reversed(args):
        ret = compose2(f, ret)
    return ret

def identity(x):    return x
def compose2(f, g): return lambda x: f(g(x))
Run Code Online (Sandbox Code Playgroud)

你可以这样使用:

from functools import partial

# equiv. of:  map (\x -> x^2) . filter (\x -> (mod x 2) == 0) $ [1..20]
compose(partial(map, lambda x: x**2), partial(filter, lambda x: x % 2 == 0))(range(1, 21))
Run Code Online (Sandbox Code Playgroud)

无可否认,它确实有效:

>>> compose(partial(map, lambda x: x**2), partial(filter, lambda x: x % 2 == 0))(range(1, 21))
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
Run Code Online (Sandbox Code Playgroud)

...但是正如您所看到的,Python 缺少某些概念,例如柯里化和可任意定义的中缀运算符,因此即使在语义上,上述代码片段与 Haskell 代码片段等效(甚至相同),但它读起来非常糟糕。


至于$运算符:它在 Python 中几乎没有相关性——它在 Haskell 中的主要目的与运算符优先级有关,这在 Python 中不是问题,因为无论如何你在大多数时间都不能真正使用运算符,并且所有构建的-in 运算符具有预定义的优先级。

$在 Haskell 中还可以用作高阶函数:

zipWith ($) [(3*), (4+), (5-)] [1,2,3]
Run Code Online (Sandbox Code Playgroud)

...在 Python 中使用它的(已弃用的)apply“组合器”复制它,将再次导致代码丑陋:

>>> list(starmap(apply, zip([lambda x: 3 * x, lambda x: 4 + x, lambda x: 5 - x], map(lambda x: [x], [1, 2, 3]))))
[3, 6, 2]
Run Code Online (Sandbox Code Playgroud)

——同样,Python 的几个基本限制在这里发挥作用:

  • 懒惰不是内置的,因此不会自动处理,因此如果不使用“强制”星图list(),就不会返回“正常”列表;
  • apply 不是(a -> b) -> a -> bbut (a1 -> a2 -> ... -> aN -> b) -> (a1, a2, ..., aN) -> b,所以你需要用[]和 use starmapnot the normal包裹列表元素map;这也是没有柯里化的结果;
  • lambda 语法很冗长,因为 Guido 的个人偏好是反对 lambdas、mapreduce等;