pythontoolz

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


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?


Solution

  • 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.