views:

130

answers:

1

I have the following code:

import operator

def stagger(l, w):
    if len(l)>=w:
        return [tuple(l[0:w])]+stagger(l[1:], w)
    return []

def pleat(f, l, w=2):
    return map(lambda p: f(*p), stagger(l, w))

if __name__=="__main__":
    print pleat(operator.add, range(10))
    print pleat(lambda x, y, z: x*y/z, range(3, 13), 3)
    print pleat(lambda x: "~%s~"%(x), range(10), 1)
    print pleat(lambda a, b, x, y: a+b==x+y, [3, 2, 4, 1, 5, 0, 9, 9, 0], 4)

Important part: Pleat takes any function and any sequence and passes the first handful of elements from that sequence into the received function as parameters.

Is there a way to do this in Haskell or am I dreaming?

+6  A: 

The type signatures below are optional:

stagger :: [a] -> Int -> [[a]]
stagger l w
    | length l >= w  =  take w l : stagger (tail l) w
    | otherwise      =  []

pleat :: ([a] -> b) -> [a] -> Int -> [b]
pleat f l w = map f $ stagger l w

main = do
    print $ pleat (\[x, y] -> x+y) [0..9] 2
    print $ pleat (\[x, y, z] -> x*y/z) [3..12] 3
    print $ pleat (\[x] -> "~" ++ show x ++ "~") [0..9] 1
    print $ pleat (\[a, b, x, y] -> a+b == x+y) [3, 2, 4, 1, 5, 0, 9, 9, 0] 4

The idea is that the function is explicit about taking a list of unknown length as an argument, so it is not very type-safe. But it is pretty much a 1-to-1 mapping of the Python code.

Peaker
Is there a way to write it so you can pass in (+) instead of (\[x,y] -> x+y) ?
Legatou
@Legatou: no. Except for spelling it differently: `lift2 f [x,y] = f x y`, `print $ pleat (lift2 (+)) [0..9] 2`. Haskell doesn't do polyvariadic functions (typeclass hackers will tell you otherwise, but then it changes to "doesn't do them well"). There is always a way to state clearly what you mean without them.
luqui
I accept this answer as valid... though depressing. I was kinda hoping I could dynamically assess the parameter count the way I eventually did here: http://www.ishpeck.com/4squirrel/pleat.html
Ishpeck
Maybe the word 'dynamic' is a clue that Haskell doesn't do it that way?
Nathan Sanders
@ Legatou Although it is not exactly the same, that function is atleast a subfunction of Prelude.sum. So you can substitute (\[x,y] -> x+y) for sum ...
HaskellElephant