Skip to content

Commit 0de7e87

Browse files
committed
Fix documentation
1 parent dbfcfca commit 0de7e87

File tree

6 files changed

+127
-56
lines changed

6 files changed

+127
-56
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# better-functools
2-
Improving functional programming ergonomics in Python.
2+
Better functools improves functional programming ergonomics in Python
3+
4+
## Installation
5+
```
6+
$ pip install better-functools
7+
```
8+
9+
## Background
310

411
The library introduces 2 different operators for use with functions:
512
- `|` which we'll call "pipe"

better_functools/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
"""More functools improves functional programming ergonomics in Python
1+
"""Better functools improves functional programming ergonomics in Python
2+
3+
## Installation
4+
```
5+
$ pip install better-functools
6+
```
7+
8+
## Background
29
310
The library introduces 2 different operators for use with functions:
411
- `|` which we'll call "pipe"

better_functools/apply.py

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,7 @@ def _call(*args: P.args, **kwargs: P.kwargs) -> R:
107107

108108

109109
@singleton
110-
class star_args:
111-
"""Convert a function with positional args to one that takes a single tuple.
112-
113-
This is useful when used with `better_functools.pipe.Pipeline`.
114-
115-
>>> def add(x: int, y: int) -> int:
116-
... return x + y
117-
>>> (add @ star_args)((1, 2))
118-
"""
119-
110+
class _star_args:
120111
def __call__(self, fn: Callable[[Unpack[Ts]], R]) -> Callable[[tuple[Unpack[Ts]]], R]:
121112
def _fn(args: tuple[Unpack[Ts]]) -> R:
122113
return fn(*args)
@@ -126,6 +117,17 @@ def _fn(args: tuple[Unpack[Ts]]) -> R:
126117
__rmatmul__ = __call__
127118

128119

120+
star_args = _star_args
121+
"""Convert a function with positional args to one that takes a single tuple.
122+
123+
This is useful when used with `better_functools.pipe.Pipeline`.
124+
125+
>>> def add(x: int, y: int) -> int:
126+
... return x + y
127+
>>> (add @ star_args)((1, 2))
128+
"""
129+
130+
129131
class invoke(Generic[Unpack[Ts]]):
130132
"""Invoke a function with the given positional args.
131133
@@ -148,23 +150,7 @@ def __call__(self, fn: Callable[[Unpack[Ts]], R]) -> R:
148150
__rmatmul__ = __call__
149151

150152

151-
@singleton
152-
class func:
153-
"""Useful for creating a partial function of an argument
154-
which is not the last and not named.
155-
156-
Suppose we have a `fn: (a, b, c) -> d`
157-
arg(fn): (b, c) -> ((a) -> d)
158-
159-
>>> def mod(a: int, b: int, /) -> int:
160-
... return a % b
161-
>>> is_odd = func(mod @ func.arg(int) @ bind(2)) @ compose(bool)
162-
>>> is_odd @ invoke(5)
163-
True
164-
>>> is_odd(4)
165-
False
166-
"""
167-
153+
class _func:
168154
@dataclass
169155
class arg(Generic[T]):
170156
type_: type[T]
@@ -184,31 +170,24 @@ def __call__(self, fn: Callable[[], Callable[[T], R]]) -> Callable[[T], R]:
184170
return fn()
185171

186172

187-
@singleton
188-
class nvl:
189-
"""None-Coalescing function.
190-
191-
`nvl` is used in 2 ways.
173+
func = _func()
174+
"""Useful for creating a partial function of an argument
175+
which is not the last and not named.
192176
193-
When used with `@` it checks the result of the left-hand side expression
194-
and ignores further `@` operations if `None`.
177+
Suppose we have a `fn: (a, b, c) -> d`
178+
arg(fn): (b, c) -> ((a) -> d)
195179
196-
When called it cleans up the result of an `@ nvl` chain.
180+
>>> def mod(a: int, b: int, /) -> int:
181+
... return a % b
182+
>>> is_odd = func(mod @ func.arg(int) @ bind(2)) @ compose(bool)
183+
>>> is_odd @ invoke(5)
184+
True
185+
>>> is_odd(4)
186+
False
187+
"""
197188

198-
The operation should be used as
199-
200-
nvl(expr1 @ nvl @ expr2 @ nvl @ ...)
201-
202-
>>> def squared(n: int) -> int:
203-
... return n * n
204-
>>> def squared_or_none(v: int | None):
205-
... return nvl(v @ nvl @ squared)
206-
>>> squared_or_none(5)
207-
25
208-
>>> squared_or_none(None)
209-
None
210-
"""
211189

190+
class _nvl:
212191
def __call__(self, v: Self | T) -> T | None:
213192
if isinstance(v, type(self)):
214193
return None
@@ -231,6 +210,31 @@ def __rmatmul__(self, left: T | None) -> T | Self:
231210
return left
232211

233212

213+
nvl = _nvl()
214+
"""None-Coalescing function.
215+
216+
`nvl` is used in 2 ways.
217+
218+
When used with `@` it checks the result of the left-hand side expression
219+
and ignores further `@` operations if `None`.
220+
221+
When called it cleans up the result of an `@ nvl` chain.
222+
223+
The operation should be used as
224+
225+
nvl(expr1 @ nvl @ expr2 @ nvl @ ...)
226+
227+
>>> def squared(n: int) -> int:
228+
... return n * n
229+
>>> def squared_or_none(v: int | None):
230+
... return nvl(v @ nvl @ squared)
231+
>>> squared_or_none(5)
232+
25
233+
>>> squared_or_none(None)
234+
None
235+
"""
236+
237+
234238
def static(fn: Callable[Concatenate[T, P], R]) -> Callable[P, apply[Callable[[T], R]]]:
235239
"""*Experimental*: Make a bound method static.
236240

docs/apply.html

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,52 @@ <h1 class="title">Module <code>better_functools.apply</code></h1>
4040
<section>
4141
</section>
4242
<section>
43+
<h2 class="section-title" id="header-variables">Global variables</h2>
44+
<dl>
45+
<dt id="better_functools.apply.func"><code class="name">var <span class="ident">func</span> : Callable[[T], R]</code></dt>
46+
<dd>
47+
<div class="desc"><p>Useful for creating a partial function of an argument
48+
which is not the last and not named.</p>
49+
<p>Suppose we have a <code>fn: (a, b, c) -&gt; d</code>
50+
arg(fn): (b, c) -&gt; ((a) -&gt; d)</p>
51+
<pre><code class="language-python-repl">&gt;&gt;&gt; def mod(a: int, b: int, /) -&gt; int:
52+
... return a % b
53+
&gt;&gt;&gt; is_odd = func(mod @ func.arg(int) @ bind(2)) @ compose(bool)
54+
&gt;&gt;&gt; is_odd @ invoke(5)
55+
True
56+
&gt;&gt;&gt; is_odd(4)
57+
False
58+
</code></pre></div>
59+
</dd>
60+
<dt id="better_functools.apply.nvl"><code class="name">var <span class="ident">nvl</span> : T | None</code></dt>
61+
<dd>
62+
<div class="desc"><p>None-Coalescing function.</p>
63+
<p><code><a title="better_functools.apply.nvl" href="#better_functools.apply.nvl">nvl</a></code> is used in 2 ways.</p>
64+
<p>When used with <code>@</code> it checks the result of the left-hand side expression
65+
and ignores further <code>@</code> operations if <code>None</code>.</p>
66+
<p>When called it cleans up the result of an <code>@ nvl</code> chain.</p>
67+
<p>The operation should be used as</p>
68+
<p>nvl(expr1 @ nvl @ expr2 @ nvl @ &hellip;)</p>
69+
<pre><code class="language-python-repl">&gt;&gt;&gt; def squared(n: int) -&gt; int:
70+
... return n * n
71+
&gt;&gt;&gt; def squared_or_none(v: int | None):
72+
... return nvl(v @ nvl @ squared)
73+
&gt;&gt;&gt; squared_or_none(5)
74+
25
75+
&gt;&gt;&gt; squared_or_none(None)
76+
None
77+
</code></pre></div>
78+
</dd>
79+
<dt id="better_functools.apply.star_args"><code class="name">var <span class="ident">star_args</span> : Callable[[tuple[Unpack[Ts]]], R]</code></dt>
80+
<dd>
81+
<div class="desc"><p>Convert a function with positional args to one that takes a single tuple.</p>
82+
<p>This is useful when used with <code><a title="better_functools.pipe.Pipeline" href="pipe.html#better_functools.pipe.Pipeline">Pipeline</a></code>.</p>
83+
<pre><code class="language-python-repl">&gt;&gt;&gt; def add(x: int, y: int) -&gt; int:
84+
... return x + y
85+
&gt;&gt;&gt; (add @ star_args)((1, 2))
86+
</code></pre></div>
87+
</dd>
88+
</dl>
4389
</section>
4490
<section>
4591
<h2 class="section-title" id="header-functions">Functions</h2>
@@ -119,7 +165,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
119165
<pre><code class="python">class apply(Generic[T_APPLY]):
120166
&#34;&#34;&#34;Make a function callable by using `@` operator.
121167

122-
This is the `@` version of `... | fn` in `more_functools.pipe.Composition`.
168+
This is the `@` version of `... | fn` in `better_functools.pipe.Composition`.
123169

124170
&gt;&gt;&gt; &#34;1234&#34; @ apply(int)
125171
1234
@@ -139,7 +185,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
139185
__rmatmul__ = __call__</code></pre>
140186
</details>
141187
<div class="desc"><p>Make a function callable by using <code>@</code> operator.</p>
142-
<p>This is the <code>@</code> version of <code>... | fn</code> in <code>more_functools.pipe.Composition</code>.</p>
188+
<p>This is the <code>@</code> version of <code>... | fn</code> in <code><a title="better_functools.pipe.Composition" href="pipe.html#better_functools.pipe.Composition">Composition</a></code>.</p>
143189
<pre><code class="language-python-repl">&gt;&gt;&gt; &quot;1234&quot; @ apply(int)
144190
1234
145191
</code></pre></div>
@@ -209,7 +255,7 @@ <h3>Class variables</h3>
209255
class compose(Generic[T, R]):
210256
&#34;&#34;&#34;Compose functions.
211257

212-
This is similar to `more_functools.pipe.Composition`,
258+
This is similar to `better_functools.pipe.Composition`,
213259
but allows it to be done with `@`.
214260

215261
&gt;&gt;&gt; def add(x: int, y: int) -&gt; int:
@@ -230,7 +276,7 @@ <h3>Class variables</h3>
230276
__rmatmul__ = __call__</code></pre>
231277
</details>
232278
<div class="desc"><p>Compose functions.</p>
233-
<p>This is similar to <code>more_functools.pipe.Composition</code>,
279+
<p>This is similar to <code><a title="better_functools.pipe.Composition" href="pipe.html#better_functools.pipe.Composition">Composition</a></code>,
234280
but allows it to be done with <code>@</code>.</p>
235281
<pre><code class="language-python-repl">&gt;&gt;&gt; def add(x: int, y: int) -&gt; int:
236282
... return x + y
@@ -307,6 +353,13 @@ <h3>Ancestors</h3>
307353
<li><code><a title="better_functools" href="index.html">better_functools</a></code></li>
308354
</ul>
309355
</li>
356+
<li><h3><a href="#header-variables">Global variables</a></h3>
357+
<ul class="">
358+
<li><code><a title="better_functools.apply.func" href="#better_functools.apply.func">func</a></code></li>
359+
<li><code><a title="better_functools.apply.nvl" href="#better_functools.apply.nvl">nvl</a></code></li>
360+
<li><code><a title="better_functools.apply.star_args" href="#better_functools.apply.star_args">star_args</a></code></li>
361+
</ul>
362+
</li>
310363
<li><h3><a href="#header-functions">Functions</a></h3>
311364
<ul class="">
312365
<li><code><a title="better_functools.apply.static" href="#better_functools.apply.static">static</a></code></li>

docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ <h3 id="better_functoolspipe"><code><a title="better_functools.pipe" href="pipe.
5454
So <code>Pipeline(v) | fn</code> is equal to <code>Pipeline(fn(v))</code>.</p>
5555
<p><code>| Pipeline.unwrap</code> is finally used to unwrap the <code>Pipeline</code> and extract the value.</p>
5656
<h3 id="better_functoolsapply"><code><a title="better_functools.apply" href="apply.html">better_functools.apply</a></code></h3>
57-
<p><code>more_functools.apply</code> includes a number of functions that implements <code>@</code>.</p>
57+
<p><code><a title="better_functools.apply" href="apply.html">better_functools.apply</a></code> includes a number of functions that implements <code>@</code>.</p>
5858
<p>For example, <code>map @ bind(prod)</code> means bind <code>prod</code> to the first arg of <code>map</code>.
5959
More apply functions can be called directly too, the above expression is equivalent to
6060
<code>bind(prod)(map)</code>.</p>

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "better-functools"
7-
version = "0.1.0"
7+
version = "0.2.0"
88
authors = [{ name = 'Jamie Chang', email = 'jamie.cheng.chang@gmail.com' }]
99
maintainers = [{ name = 'Jamie Chang', email = 'jamie.cheng.chang@gmail.com' }]
1010
description = "Functional Programming Ergonomics in Python."

0 commit comments

Comments
 (0)