我昨天开始使用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风格的方法是什么?
答案 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)
否则使用已建议的方式。