将列表元素作为参数传递给curried函数

Ish*_*eck 9 haskell currying

这里还是一个Haskell新手.我知道这足以让我自己陷入错误假设的困境.如果我有以下功能......

quadsum w x y z = w+x+y+z
Run Code Online (Sandbox Code Playgroud)

我想要一个可以获取列表的函数,将每个元素用作指定函数中的参数quadsum,并返回一个curried函数供以后使用.

我一直在努力尝试......

magicalFunctionMaker f [] = (f)
magicalFunctionMaker f (x:xs) = magicalFunctionMaker (f x) xs
Run Code Online (Sandbox Code Playgroud)

希望能够做到这一点......

magicalFunctionMaker (quadsum) [4,3,2]
Run Code Online (Sandbox Code Playgroud)

获得像...这样的咖喱功能:

(((quadsum 4) 3) 2)
Run Code Online (Sandbox Code Playgroud)

或者,或者,致电:

magicalFunctionMaker (quadsum) [4,3,2,1]
Run Code Online (Sandbox Code Playgroud)

导致...

((((quadsum 4) 3) 2) 1)
Run Code Online (Sandbox Code Playgroud)

这可能吗?我是多么误导?

Pau*_*son 7

我认为你误解了Haskell类型系统.

首先,你的"quadsum"功能已经过去了.您可以编写"quadsum 4 3"并返回一个函数,该函数期望2和1作为额外参数.当你写"quadsum 4 3 2 1"相当于"((((quadsum 4)3)2)1)"时.

在Haskell中,整数列表具有与整数或元组不同的类型,例如"(4,3,2,1)".鉴于此,很难理解你想要做什么.如果你写这个应该发生什么?

magicalFunctionMaker quadsum [5,4,3,2,1]
Run Code Online (Sandbox Code Playgroud)

你的"magicalFunctionMaker"看起来很像"foldl",除了你给foldl的函数只有两个参数.所以你可以写:

mySum = foldl (+) 0
Run Code Online (Sandbox Code Playgroud)

这将返回一个获取列表并对元素求和的函数.

(顺便说一句,一旦你了解了这一点,了解foldl和foldr之间的区别.

编辑:

重新阅读你的问题,我想你正试图得到:

magicalFunctionMaker quadSum [4,3,2,1] :: Integer
magicalFunctionMaker quadSum [4,3,2] :: Integer -> Integer
Run Code Online (Sandbox Code Playgroud)

这是不可能的,因为magicalFunctionMaker的类型将取决于list参数的长度,这意味着动态类型.正如有人所说,多变量函数可以做一些接近这个的事情(尽管没有列表参数),但是这需要相当多的类型hackery的milli-olegs.


Joh*_*n L 4

保罗·约翰逊的回答几乎涵盖了这一点。做就是了

quadsum 4 3 2
Run Code Online (Sandbox Code Playgroud)

结果将是您想要的函数,类型为Integer -> Integer

但有时这还不够好。有时您会得到数字列表,但您不知道列表有多长,并且需要将这些元素应用到您的函数中。这个有点难。你不能这样做:

magicalFunction2 f [] = f
magicalFunction2 f (x1:x2:xs) = f x1 x2
Run Code Online (Sandbox Code Playgroud)

因为结果有不同的类型。在第一种情况下,结果需要两个参数,而在第二种情况下,它是一个完全应用的函数,因此不允许使用更多参数。在这种情况下,最好的办法是保留列表和原始函数,直到有足够的参数可用:

type PAPFunc f a result = Either (f, [a]) result

magicfunc f xs = Left (f,xs)

apply (Left (f,xs)) ys = Left (f,xs++ys)
apply p _              = p

simp2 :: PAPFunc (a->a->b) a b -> PAPFunc (a->a->b) a b
simp2 (Left (f,(x1:x2:xs))) = Right (f x1 x2)
simp2 p = p
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

Main> let j = magicfunc (+) []
Main> let m = apply j [1]
Main> let n = apply m [2,3]

Main> either (const "unfinished") show $ simp2 m
"unfinished"
Main> either (const "unfinished") show $ simp2 n
"3"
Run Code Online (Sandbox Code Playgroud)

每个数量都需要一个单独的简化函数,这个问题最容易通过 Template Haskell 解决。

在 Haskell 中使用参数列表(而不是列表参数)往往非常尴尬,因为多个结果都有不同的类型,并且很少支持具有可变数量的不同类型参数的集合。我见过三大类解决方案:

  1. 分别为每种情况显式编码(很快就会变得很多工作)。

  2. 哈斯克尔模板。

  3. 类型系统黑客攻击。

我的回答主要涉及如何减少痛苦。2和3不适合胆小的人。

编辑:事实证明,Hackage 上有一些 与此问题相关的软件包。使用“迭代者”:

import qualified Data.Iteratee as It
import Control.Applicative

magic4 f = f <$> It.head <*> It.head <*> It.head <*> It.head

liftedQuadsum = magic4 quadsum
-- liftedQuadsum is an iteratee, which is essentially an accumulating function
-- for a list of data

Main> p <- It.enumChunk (It.Chunk [1]) liftedQuadsum
Main> It.run p
*** Exception: EofException
Main> q <- It.enumChunk (It.Chunk [2,3,4]) p
Main> It.run q
10
Run Code Online (Sandbox Code Playgroud)

但“iteratee”和“enumerator”可能有点矫枉过正。