Still a Haskell newbie here. I know just enough to get myself into trouble with wrong assumptions. If I have the following function...
quadsum w x y z = w+x+y+z
I want a function that can take a list, use each element as a parameter in a specified function like quadsum
, and return a curried function for later use.
I've been trying something to the effect of...
magicalFunctionMaker f [] = (f)
magicalFunctionMaker f (x:xs) = magicalFunctionMaker (f x) xs
With the hope of being able to do this...
magicalFunctionMaker (quadsum) [4,3,2]
Getting a curried function like...:
(((quadsum 4) 3) 2)
Or, alternatively, call:
magicalFunctionMaker (quadsum) [4,3,2,1]
Resulting in...
((((quadsum 4) 3) 2) 1)
Is this possible? How misguided am I?
Paul Johnson's answer pretty much covers it. Just do
quadsum 4 3 2
and the result will be the function you want, with type Integer -> Integer
.
But sometimes this isn't good enough. Sometimes you get lists of numbers, you don't know how long the lists are, and you need to apply the elements to your function. This is a bit harder. You can't do:
magicalFunction2 f [] = f
magicalFunction2 f (x1:x2:xs) = f x1 x2
because the results have different types. In the first case the result needs two arguments, and in the second it's a fully-applied function so no more arguments are allowed. In this case, the best thing to do is hold onto the list and your original function until enough arguments are available:
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
now you can do:
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"
You'll need a separate simplify function for each arity, a problem that's most easily fixed by Template Haskell.
Using lists of arguments (as opposed to an argument of lists) tends to be very awkward in Haskell because the multiple results all have different types, and there's very little support for collections with variable numbers of differently-typed arguments. I've seen three general categories of solutions:
Explicitly code for each case separately (quickly becomes a lot of work).
Template Haskell.
Type system hackery.
My answer mostly deals with trying to make 1 less painful. 2 and 3 are not for the faint of heart.
Edit: It turns out that there are some packages on Hackage that are related to this problem. Using "iteratee":
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
But "iteratee" and "enumerator" are likely overkill though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With