13

我昨天从 haskell 开始,仍然完全迷失在这个勇敢的新世界的岸边。现在我遇到了以下问题:

假设我有一些函数对整数和另一个变量有一些魔力:

makeTuple :: Int -> a -> (Int, a)
makeTuple n x = (n, x)

现在我想将此函数应用于列表的所有元素。到目前为止没问题,因为映射也是你在 python 中的日常面包和黄油(我来自哪里)。

makeTupleList :: Int -> [a] -> [ (Int, a) ]
makeTupleList n x = map (makeTuple n) x

据我了解,二元函数 makeTuple 部分与整数 n 一起应用,因此成为一个可以映射到 x 的每个元素的一元函数。到目前为止,一切都很好。

但是当 makeTuple 函数有另一个签名时我该怎么办,比如:

makeTuple2 :: a -> Int -> (Int, a)
makeTuple2 x n = (n, x)

通向罗马的方式很多:效果相同,但方式不同。现在显然映射不再起作用了:该函数需要一个 Int 并得到一个 a。

makeTupleList2 :: Int -> [a] -> [ (Int, a) ]
makeTupleList2 n x = map (makeTuple2 n) x -- boolshit

这是意料之中的。我的-也许太pythonic-解决方法是使用另一个函数将参数传递到它们应该去的地方:

makeTupleList2 :: Int -> [a] -> [ (Int, a) ]
makeTupleList2 n x = map (\x -> makeTuple2 x n) x

问题: 当部分应用的参数不是最左边时,首选的函数式、haskell 风格的部分应用函数的方式是什么?

4

4 回答 4

16

您可以使用flip,它交换函数的第一个和第二个参数。

makeTupleList2 n x = map (flip makeTuple2 n) x

另一种选择是使用反引号语法来制作中缀运算符,然后使用运算符部分部分应用它。

maleTupleList2 n x = map (`makeTuple2` n) x

或者,正如您所说,我们可以使用 lambda 表达式。使用哪一个取决于上下文和个人品味。使用您认为最清楚的任何内容。


PS:您所做的称为部分应用程序。柯里化是将具有多个参数的函数转换为柯里化(a, b) -> c形式以便 a -> b -> c可以部分应用的过程。

于 2011-07-16T14:35:09.113 回答
1

您可以替换\x -> makeTuple2 x nflip makeTuple2 n,因为 Prelude 定义flip如下:(我的实现,不是他们的)

flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y

因此我们得到

makeTupleList2' = map . flip makeTuple2

或者,看看它只是一个元组:

makeTupleList2'' = map . (,)

另请注意(我不确定这有多有效),您可以使用 zip:

makeTupleList2''' :: a -> [b] -> [(a, b)]
makeTupleList2''' = zip . repeat
于 2011-07-16T14:33:43.537 回答
1

在这种特殊情况下,您可以使用flip makeTuple2 n,但这仅适用于具有两个参数的函数。但一般来说,我找不到你的解决方案与 lambda un-haskelly 或太 Pythonic。

于 2011-07-16T14:35:36.990 回答
1

如果您的函数只是元组构造函数:

makeTuple x y = (x,y)

(也可以写成makeTuple = (,))然后有一个特殊的扩展:

{-# LANGUAGE TupleSections #-}
makeTupleList2 n x = map (n,) x
makeTupleList2' n x = map (,n) x     -- Use n as the second component

也可以写成

makeTupleList2 n = map (n,)
makeTupleList2' n = map (,n)

否则使用已经建议的方法。

于 2011-07-16T14:49:59.070 回答