【问题标题】:Currying out of order in Haskell在 Haskell 中乱码
【发布时间】:2010-09-24 16:43:15
【问题描述】:

在 Haskell 中是否有一个优雅的表示法用于将函数的参数进行无序柯里化?

例如,如果你想用 2 除以列表的所有元素,你可以这样写

map ((/) 2) [1,2,3,4,5]

但是,要划分列表的所有元素,您似乎需要定义一个匿名函数

map (\x -> x/2) [1,2,3,4,5]

在更复杂的情况下,匿名函数很快就会变得笨拙。我知道在这种情况下 map ((*) 0.5) [1,2,3,4,5] 可以正常工作,但我很想知道 Haskell 是否有更优雅的方法来对函数的参数进行柯里化乱码?

【问题讨论】:

  • flip 和反引号与简单地使用中缀函数一起很好(正如 delnan 指出的那样)。

标签: haskell currying


【解决方案1】:

在这种特殊情况下:

Prelude> map (/2) [1..5]
[0.5,1.0,1.5,2.0,2.5]

中缀运算符不仅可以作为普通前缀函数使用,还可以部分应用于中缀形式。同样,第一个例子最好写成map (2/) [1..5]

另外,flip 不是很优雅,但仍然是普通函数的最佳选择(当您不想通过反引号将它们变成中缀时):

Prelude> let div' = (/)
Prelude> div' 2 1
2.0
Prelude> flip div' 2 1
0.5

【讨论】:

  • 这仅适用于运营商吗?任意函数呢?
  • @Gabe:正如 FUZxxl 所写,它也适用于使用中缀的函数(通过用反引号括起来)。我会提供一个例子,但他已经提供了一个。
  • 谢谢。可惜没有像 f 1 2 # 4 # 这样的语法,它与 \x y -> f 1 2 x 4 y 具有相同的效果。
  • @hosiers:实际上,对于元组,有一个扩展名:将{-# LANGUAGE TupleSections #-} 放在顶部,您可以使用('a',,1,,) 而不是\x y z -> ('a',x,1,y,z),但对于函数-我还没有看到这个。
【解决方案2】:

对于第二个,lambda 是不必要的,只需使用如下:

map (/2) [1..5]

表单 (/2) 仅表示您要访问运算符的第二个参数。第一个参数(2/) 也是可能的。这被称为 section,是一个非常有用的 hack,不仅在代码高尔夫中。你也可以在前缀函数中使用它,如果你使用它们中缀:

map (`div` 2) [1..5]

在更困难的情况下,例如 3 个或更多参数,您应该使用 lambda,因为它在大多数情况下变得更具可读性。

【讨论】:

    【解决方案3】:

    我认为您正在寻找一个通用的解决方案,例如方案中的cut。对?

    flip 函数反转函数的前 2 个参数。可能还有其他函数在做类似的任务(我对 Haskell 不太擅长……但)。

    【讨论】:

    • flip 不会反转参数列表。它只是翻转了前两个,考虑一下:flip (.) :: (a -> b) -> (b -> c) -> a -> c。 -1
    【解决方案4】:

    我自己最近遇到了very similar issue,除了使用辅助函数之外,我找不到优雅的解决方案:

    dbfunc f b c = (\a -> liftIO $ f a b c)
    deleteAllRows = do
      ask >>= dbfunc run "delete from t1" []
    

    至少这种模式在 HDBC 中很常见,以至于 dbfunc 是可重用的。

    【讨论】:

    • ask >>= liftIO . (flip . (flip run) "delete from t1" [])
    • 对于优雅的某些价值观 ;-)
    猜你喜欢
    • 2012-06-16
    • 2021-08-06
    • 2019-03-21
    • 2012-07-09
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    相关资源
    最近更新 更多