2

I would like to be able to curry merge_with:

merge_with works as I expect

>>> from cytoolz import curry, merge_with
>>> d1 = {"a" : 1, "b" : 2}
>>> d2 = {"a" : 2, "b" : 3}
>>> merge_with(sum, d1, d2)
{'a': 3, 'b': 5}

On a simple function, curry works as I expect:

>>> def f(a, b):
...     return a * b
... 
>>> curry(f)(2)(3)
6

But I'm not able to "manually" make a curried version of merge_with:

>>> curry(merge_with)(sum)(d1, d2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'dict' object is not callable
>>> curry(merge_with)(sum)(d1)(d2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'dict' object is not callable

The pre-curried version works:

>>> from cytoolz.curried import merge_with as cmerge
>>> cmerge(sum)(d1, d2)
{'a': 3, 'b': 5}

Where is my mistake?

bli
  • 7,549
  • 7
  • 48
  • 94
  • Here is me again finding a question I posted earlier while having the same question again... – bli Mar 28 '23 at 11:57

1 Answers1

3

It is because merge_with takes dicts as positional arguments:

merge_with(func, *dicts, **kwargs)

so f is the only obligatory argument, and for empty *args you get an empty dictionary:

>>> curry(merge_with)(sum)  # same as merge_with(sum)
{}

so:

curry(f)(2)(3)

is equivalent to

>>> {}(2)(3)
Traceback (most recent call last):
...
TypeError: 'dict' object is not callable

You'll have to explicit and define helper

def merge_with_(f):
    def _(*dicts, **kwargs):
        return merge_with(f, *dicts, **kwargs)
    return _

which can be used as you want:

>>> merge_with_(sum)(d1, d2)
{'a': 3, 'b': 5}

or:

def merge_with_(f, d1, d2, *args, **kwargs):
    return merge_with(f, d1, d2, *args, **kwargs)

which can both

>>> curry(merge_with_)(sum)(d1, d2)
{'a': 3, 'b': 5}

and:

>>> curry(merge_with_)(sum)(d1)(d2)
{'a': 3, 'b': 5}
Alper t. Turker
  • 34,230
  • 9
  • 83
  • 115