How to make a curry version of map that always returns list using toolz

849 Views Asked by At

If I import toolz using

from toolz.curried import *

then map will automatically becomes curried form, so

map(func,[[1,2],[3,4]])

can be written as

map(func)([[1,2],[3,4]])

but curried map always return an iterable. I way to define an curried lmap which always return list. But simple try

lmap=compose(list,map)

will not work, for example

lmap(len)([[1,2],[3,4]])

will give

---------------------------------------------------------------------------
TypeError Traceback (most recent call last) in () ----> 1 lmap(len)([[1,2],[3,4]])

C:\ProgramData\Anaconda3\lib\site-packages\toolz\functoolz.py in
call(self, *args, **kwargs)
466 ret = self.first(*args, **kwargs)
467 for f in self.funcs:
--> 468 ret = f(ret)
469 return ret
470

TypeError: 'curry' object is not iterable

So how to define a curried lmap?

2

There are 2 best solutions below

0
Alper t. Turker On BEST ANSWER

You're calling it wrong way. map being passed to compose is curried, but not a whole expression. When you call it like

lmap(len)([[1,2],[3,4]])

it passes len to lmap it returns toolz.functoolz.curry equivalent to

map(len)

and then tries to call list on it:

list(map(len))

which obviously cannot work. If it didn't fail complete expression would be equivalent to:

list(map(len))([[1,2],[3,4]])

while the call you're looking for is:

list(map(len), [[1,2],[3,4]])

So in fact currying doesn't make much sense here.

You probably want something around these lines:

def lmap(g): return compose(list, map(g)) 

which would be callable as you want:

>>> lmap(len)([[1,2],[3,4]])
[2, 2]

but to honest the problem looks a bit artificial - the biggest advantage of toolz in uniform laziness. Converting to list throws away most of that.

2
qwitwa On

This question is currently top in google results for the toolz error 'curry' object is not iterable. One additional way to trigger this error message not yet mentioned here is to attempt to use toolz.curried.pipe with curried iterators as if pipe itself were curried:

>>> transform = pipe(
    map(lambda x: x + 1),
    map(lambda x: x + x)
    )
>>> list(transform([3,4,5]))
TypeError: 'curry' object is not iterable

Here the first curried map is being passed as the final argument to the second; despite being reexported from the curried namespace, pipe is not curried. The solution is to upgrade to toolz version 0.10.0 if not already using it and use toolz.curried.compose_left instead which is effectively a curried pipe:

>>> transform = compose_left(
    map(lambda x: x + 1),
    map(lambda x: x + x)
    )
>>> list(transform([3,4,5]))
[8, 10, 12]