Search code examples
haskelllambdafold

Properly implementing a function inside foldl's lambda function


I'm new to haskell, trying to learn by solving some puzzles online.

I have this function

crossCopyPaste t (as, bs) = (take t as ++ drop t bs, take t bs ++ drop t as) 

which just takes a number t and a pair of lists (as, bs)

I have another function

crossover ns xs ys

which takes a list of ints ns and two lists xs ys

what I want crossover to do is take first element of list ns say t'

run crossCopyPaste t' (xs, ys), take the result say result1

get the next number in the list ns say t''

and run crossCopyPaste t'' (fst result1, snd result1) (its result will be result2)

next few would look like this

crossCopyPaste t''' (fst result2, snd result2)

crossCopyPaste t'''' (fst result3, snd result3)

and continuously do this until there aren't any elements left to cover in the list ns

So I thought of using foldl since it takes a function, starting element and a list and applys all like this

foldl (+) 0 (1:2:3:[])
      =  foldl (+) (0 + 1)             (2:3:[])
      =  foldl (+) ((0 + 1) + 2)       (3:[])
      =  foldl (+) (((0 + 1) + 2) + 3) []
      =            (((0 + 1) + 2) + 3)

but I don't know how I'd go about implementing it in the context I described above.


this is the crossover I thought would work

crossover ns xs ys = foldl (\acc t -> crossCopyPaste t (xs, ys)) 0 ns  

Solution

  • Let's start by taking a look at the signature of your function crossCopyPaste. A quick check in ghci shows this

    > :t crossCopyPaste
    crossCopyPaste :: Int -> ([a], [a]) -> ([a], [a])
    

    And the signature of foldl

    > :t foldl
    foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
    

    So from that we can see that the function passed to foldl must output the same type that it is passed. Since crossCopyPaste outputs a value of type ([a], [a]) the folding function needs to accept a value of that type as an input (the accumulator). So your lambda needs to look something like this:

    (\(accx, accy) t -> crossCopyPaste t (accx, accy))
    

    Note that since we don't actually need to split the values of the tuple there's no need to pattern match on them and we can re-write the lambda as

    (\acc t -> crossCopyPaste t acc)
    

    Now, the initial value for the accumulator just needs to be the initial value of xs and ys. So we can put it all together like this

    crossover ns xs ys = foldl (\acc t -> crossCopyPaste t acc) (xs, ys) ns