0
# Curried Functions
1
2
All toolz functions available in curried form for automatic partial application. The curried namespace enables more concise functional programming style and easier function composition by allowing functions to be called with fewer arguments than required.
3
4
## Package Access
5
6
```python
7
import toolz.curried as toolz
8
# All functions automatically support partial application
9
10
# Alternative imports
11
from toolz.curried import map, filter, groupby, compose, merge
12
from toolz import curried # Access as curried.map, curried.filter, etc.
13
14
# Operator functions import
15
from toolz.curried.operator import add, mul, eq, lt, getitem
16
# Or access as toolz.add, toolz.mul, etc. when using main import
17
```
18
19
## Capabilities
20
21
### Automatic Partial Application
22
23
Every function in the curried namespace supports partial application - calling a function with fewer arguments than required returns a new function expecting the remaining arguments.
24
25
```python { .api }
26
# All main toolz functions available as curried versions:
27
# - All itertoolz functions (groupby, take, partition, etc.)
28
# - All functoolz functions (compose, pipe, memoize, etc.)
29
# - All dicttoolz functions (merge, assoc, get_in, etc.)
30
# - All recipe functions (countby, partitionby)
31
# - All operator module functions (add, mul, eq, etc.)
32
```
33
34
### Enhanced Operator Functions
35
36
The curried namespace includes all Python `operator` module functions in curried form, plus additional enhanced versions.
37
38
```python { .api }
39
# Curried operator functions available:
40
# add, sub, mul, truediv, floordiv, mod, pow, and_, or_, xor,
41
# lshift, rshift, inv, neg, pos, abs, eq, ne, lt, le, gt, ge,
42
# getitem, setitem, delitem, contains, countOf, indexOf, etc.
43
44
def merge(*dicts, **kwargs):
45
"""Enhanced curried merge function."""
46
47
def merge_with(func, *dicts, **kwargs):
48
"""Enhanced curried merge_with function."""
49
```
50
51
## Usage Examples
52
53
### Curried Iterator Operations
54
55
```python
56
import toolz.curried as toolz
57
58
# Create specialized functions through partial application
59
take_5 = toolz.take(5) # Function that takes first 5 elements
60
evens = toolz.filter(lambda x: x % 2 == 0) # Function that filters even numbers
61
double = toolz.map(lambda x: x * 2) # Function that doubles all elements
62
63
# Use in pipelines
64
data = range(20)
65
result = toolz.pipe(
66
data,
67
evens, # filter even numbers
68
take_5, # take first 5
69
double, # double each
70
list # convert to list
71
)
72
# [0, 4, 8, 12, 16]
73
74
# Create reusable grouping functions
75
group_by_length = toolz.groupby(len)
76
group_by_first_letter = toolz.groupby(lambda word: word[0])
77
78
words = ['apple', 'apricot', 'banana', 'blueberry', 'cherry']
79
by_length = group_by_length(words)
80
# {5: ['apple'], 7: ['apricot', 'cherry'], 6: ['banana'], 9: ['blueberry']}
81
```
82
83
### Curried Function Composition
84
85
```python
86
import toolz.curried as toolz
87
88
# Create processing pipeline with curried functions
89
def process_numbers(data):
90
"""Process list of numbers with functional pipeline."""
91
return toolz.pipe(
92
data,
93
toolz.filter(lambda x: x > 0), # positive numbers only
94
toolz.map(lambda x: x * x), # square each number
95
toolz.groupby(lambda x: x % 10), # group by last digit
96
toolz.valmap(list), # convert iterators to lists
97
lambda d: toolz.keyfilter(lambda k: k in [1, 4, 9], d) # perfect squares mod 10
98
)
99
100
numbers = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
101
result = process_numbers(numbers)
102
# {1: [1], 4: [4], 9: [9]}
103
104
# Compose reusable transformations
105
text_processor = toolz.compose(
106
list, # convert to list
107
toolz.map(str.upper), # uppercase each word
108
toolz.filter(lambda w: len(w) > 3), # words longer than 3 chars
109
str.split # split into words
110
)
111
112
text = "the quick brown fox jumps over the lazy dog"
113
processed = text_processor(text)
114
# ['QUICK', 'BROWN', 'JUMPS', 'OVER', 'LAZY']
115
```
116
117
### Curried Dictionary Operations
118
119
```python
120
import toolz.curried as toolz
121
122
# Create specialized dictionary operations
123
add_timestamp = toolz.assoc('timestamp', '2023-01-01')
124
get_user_name = toolz.get_in(['user', 'name'])
125
double_values = toolz.valmap(lambda x: x * 2)
126
127
# Apply to data
128
user_data = {'user': {'name': 'Alice', 'id': 123}, 'score': 85}
129
enhanced = add_timestamp(user_data)
130
name = get_user_name(enhanced)
131
# 'Alice'
132
133
# Dictionary processing pipeline
134
inventory = {'apples': 50, 'bananas': 30, 'oranges': 40}
135
processed_inventory = toolz.pipe(
136
inventory,
137
double_values, # double all quantities
138
toolz.keymap(str.upper), # uppercase all keys
139
toolz.valfilter(lambda x: x >= 70) # keep items with 70+ quantity
140
)
141
# {'APPLES': 100, 'ORANGES': 80}
142
```
143
144
### Advanced Curried Patterns
145
146
```python
147
import toolz.curried as toolz
148
from operator import add, mul
149
150
# Create mathematical operation pipelines
151
numbers = [1, 2, 3, 4, 5]
152
153
# Curried operator functions
154
add_10 = toolz.add(10) # curried addition
155
multiply_3 = toolz.mul(3) # curried multiplication
156
157
transformed = toolz.pipe(
158
numbers,
159
toolz.map(multiply_3), # multiply each by 3
160
toolz.map(add_10), # add 10 to each
161
list
162
)
163
# [13, 16, 19, 22, 25]
164
165
# Data analysis pipeline
166
sales_data = [
167
{'product': 'laptop', 'price': 1000, 'quantity': 2},
168
{'product': 'mouse', 'price': 25, 'quantity': 10},
169
{'product': 'keyboard', 'price': 75, 'quantity': 5}
170
]
171
172
# Create analysis functions
173
get_total_value = lambda item: item['price'] * item['quantity']
174
is_high_value = lambda total: total >= 200
175
176
analysis = toolz.pipe(
177
sales_data,
178
toolz.map(lambda item: toolz.assoc(item, 'total', get_total_value(item))),
179
toolz.filter(toolz.compose(is_high_value, toolz.get('total'))),
180
toolz.groupby(toolz.get('product')),
181
toolz.valmap(lambda items: sum(item['total'] for item in items))
182
)
183
# {'laptop': 2000, 'keyboard': 375}
184
```
185
186
### Curried Function Building
187
188
```python
189
import toolz.curried as toolz
190
191
# Build complex operations from simple curried functions
192
def create_data_processor(min_value, transform_fn, group_key_fn):
193
"""Factory function that creates data processors."""
194
return toolz.compose(
195
lambda groups: toolz.valmap(list, groups), # materialize groups
196
toolz.groupby(group_key_fn), # group by key function
197
toolz.map(transform_fn), # transform each item
198
toolz.filter(lambda x: x >= min_value) # filter by minimum value
199
)
200
201
# Create specific processors
202
score_processor = create_data_processor(
203
min_value=70,
204
transform_fn=lambda x: x * 1.1, # 10% bonus
205
group_key_fn=lambda x: 'high' if x >= 90 else 'medium'
206
)
207
208
scores = [65, 75, 85, 95, 88, 92, 68, 78, 96]
209
processed = score_processor(scores)
210
# {'medium': [82.5, 93.5, 96.8, 85.8], 'high': [104.5, 101.2, 105.6]}
211
212
# Combine multiple curried operations
213
text_analyzer = toolz.compose(
214
lambda d: toolz.valmap(len, d), # count words in each group
215
toolz.groupby(len), # group by word length
216
toolz.map(str.lower), # lowercase all words
217
toolz.filter(str.isalpha), # alphabetic words only
218
str.split # split into words
219
)
220
221
text = "The Quick Brown Fox Jumps Over The Lazy Dog!"
222
analysis = text_analyzer(text)
223
# {3: 4, 5: 2, 4: 2, 3: 1} # word counts by length
224
```
225
226
## Benefits of Curried Functions
227
228
### Improved Readability
229
230
```python
231
# Standard toolz
232
from toolz import filter, map, groupby
233
result = list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, data)))
234
235
# Curried toolz
236
import toolz.curried as toolz
237
even_doubler = toolz.compose(list, toolz.map(lambda x: x * 2), toolz.filter(lambda x: x % 2 == 0))
238
result = even_doubler(data)
239
```
240
241
### Function Reuse
242
243
```python
244
import toolz.curried as toolz
245
246
# Create reusable components
247
high_scores = toolz.filter(lambda x: x >= 90)
248
grade_counts = toolz.compose(toolz.valmap(len), toolz.groupby(lambda x: 'A' if x >= 90 else 'B'))
249
250
# Apply to different datasets
251
student_scores = [85, 92, 78, 96, 88, 94]
252
test_scores = [91, 87, 93, 89, 95, 86]
253
254
high_students = list(high_scores(student_scores)) # [92, 96, 94]
255
high_tests = list(high_scores(test_scores)) # [91, 93, 95]
256
257
student_grades = grade_counts(student_scores) # {'B': 3, 'A': 3}
258
test_grades = grade_counts(test_scores) # {'A': 3, 'B': 3}
259
```
260
261
### Pipeline Composition
262
263
```python
264
import toolz.curried as toolz
265
266
# Build complex pipelines from simple parts
267
data_cleaner = toolz.compose(
268
toolz.unique, # remove duplicates
269
toolz.filter(lambda x: x > 0), # positive values only
270
toolz.map(abs) # absolute values
271
)
272
273
aggregator = toolz.compose(
274
lambda d: toolz.merge(d, {'total': sum(d.values())}), # add total
275
toolz.frequencies, # count frequencies
276
data_cleaner # clean first
277
)
278
279
messy_data = [-2, 1, -1, 2, 1, 3, 2, -3, 1]
280
result = aggregator(messy_data)
281
# {1: 3, 2: 2, 3: 1, 'total': 6}