部分申请从左到右

时间:2011-07-16 14:28:42

标签: haskell partial-application

我昨天开始使用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并获得一个。

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

这是可以预料的。我的-maybe太pythonic- workaround正在使用另一个函数来传递参数:

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

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

4 个答案:

答案 0 :(得分:16)

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

makeTupleList2 n x = map (flip makeTuple2 n) x

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

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

或者,正如您所说,我们可以使用lambda表达式。使用哪一个取决于背景和个人品味。使用你认为最清楚的任何东西。


PS:您正在做的事情称为部分应用。 Currying是将多个参数(a, b) -> c转换为 curried form a -> b -> c的函数转换的过程,以便可以部分应用它。

答案 1 :(得分:1)

您可以将\x -> makeTuple2 x n替换为flip 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

答案 2 :(得分:1)

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

答案 3 :(得分: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)

否则使用已建议的方式。