You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+9Lines changed: 9 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,6 +145,15 @@ The same applies if you need the macro parts of `unpythonic` (i.e. import anythi
145
145
- Drop support for deprecated argument format for `raisef`. Now the usage is `raisef(exc)` or `raisef(exc, cause=...)`. These correspond exactly to `raise exc` and `raise exc from ...`, respectively.
- Multiple return values are now denoted as `Values`, available from the top-level namespace of `unpythonic`.
150
+
- The `Values` constructor accepts both positional and named arguments. Passing in named arguments creates **named return values**. This completes the symmetry between argument passing and returns.
151
+
- Most of the time, it's still fine to return a tuple and destructure that; but in contexts where it is important to distinguish between a single `tuple` return value and multiple return values, it is preferable to use `Values`.
152
+
- In any utilities that deal with function composition, if your intent is multiple-return-values, **it is now mandatory to return a `Values`** instead of a `tuple`:
153
+
-`curry`
154
+
-`pipe` family
155
+
-`compose` family
156
+
- All multiple-return-values in code using the `with continuations` macro. (The continuations system essentially composes continuation functions.)
148
157
- The lazy evaluation tools `lazy`, `Lazy`, and the quick lambda `f` (underscore notation for Python) are now provided by `unpythonic` as `unpythonic.syntax.lazy`, `unpythonic.lazyutil.Lazy`, and `unpythonic.syntax.f`, because they used to be provided by `macropy`, and `mcpyrate` does not provide them.
149
158
-**API differences.**
150
159
- The macros `lazy` and `f` can be imported from the syntax interface module, `unpythonic.syntax`, and the class `Lazy` is available at the top level of `unpythonic`.
Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -62,7 +62,8 @@
62
62
- For example:
63
63
- Not only a summarizing `minmax` utility, but `running_minmax` as well. The former is then just a one-liner expressed in terms of the latter.
64
64
-`foldl` accepts multiple iterables, has a switch to terminate either on the shortest or on the longest input, and takes its arguments in a curry-friendly order. It also *requires* at least one iterable, so that `curry` knows to not trigger the call until at least one iterable has been provided.
65
-
-`curry` changes Python's reduction semantics to be more similar to Haskell's, to pass extra arguments through on the right, and keep calling if an intermediate result is a function, and there are still such passed-through arguments remaining. This extends what can be expressed concisely, [for example](http://www.cse.chalmers.se/~rjmh/Papers/whyfp.html) a classic lispy `map` is `curry(lambda f: curry(foldr, composerc(cons, f), nil))`. Feed that a function and an iterable, and get a linked list with the mapped results. Note the arity mismatch; `f` is 1-to-1, but `cons` is 2-to-1.
65
+
-`curry` changes Python's reduction semantics to be more similar to Haskell's, to pass extra arguments through, and keep calling if an intermediate result is a function, and there are still such passed-through arguments remaining. This extends what can be expressed concisely, [for example](http://www.cse.chalmers.se/~rjmh/Papers/whyfp.html) a classic lispy `map` is `curry(lambda f: curry(foldr, composerc(cons, f), nil))`. Feed that a function and an iterable, and get a linked list with the mapped results. Note the arity mismatch; `f` is 1-to-1, but `cons` is 2-to-1.
66
+
-`curry` also supports our `@generic` functions, and named return values...
66
67
-**Make features work together** when it makes sense. Aim at composability. Try to make features orthogonal when reasonably possible, so that making them work together requires no extra effort. When not possible, purposefully minimizing friction in interaction between features makes for a coherent, easily understandable language extension.
67
68
68
69
-**Be concise but readable**, like in mathematics.
-``Values``, for returning multiple values and/or named return values. (This ties in to `unpythonic`'s function composition subsystem, e.g. `curry`, the `pipe` family, the `compose` family, and the `with continuations` macro.)
88
89
89
90
For detailed documentation of the language features, see [``unpythonic.syntax``](https://github.com/Technologicat/unpythonic/tree/master/doc/macros.md), especially the macros ``tco``, ``autoreturn``, ``multilambda``, ``namedlambda``, ``quicklambda``, ``let`` and ``do``.
Copy file name to clipboardExpand all lines: doc/features.md
+20-11Lines changed: 20 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -998,15 +998,17 @@ Things missing from the standard library.
998
998
-**Changed in v0.15.0.**`curry` supports both positional and named arguments, and binds arguments to function parameters like Python itself does. The call triggers when all parameters are bound, regardless of whether they were passed by position or by name, and at which step of the currying process they were passed.
999
999
-**Changed in v0.15.0.**`unpythonic`'s multiple-dispatch system (`@generic`, `@typed`) is supported. `curry` looks for an exact match first, then a match with extra args/kwargs, and finally a partial match. If there is still no match, this implies that at least one parameter would get a binding that fails the type check. In such a case `TypeError` regarding failed multiple dispatch is raised.
1000
1000
-**Changed in v0.15.0.** If the function being curried is`@generic`or`@typed`, or has type annotations on its parameters, the parameters being passed in are type-checked. A type mismatch immediately raises `TypeError`. This helps support [fail-fast](https://en.wikipedia.org/wiki/Fail-fast) in code using `curry`.
1001
-
- Passthrough when too many args (à la Haskell; or [spicy](https://github.com/Technologicat/spicy) for Racket). Positional args are passed through **on the right**.
1002
-
- If the intermediate result of a passthrough iscallable, it is (curried and) invoked on the remaining args and kwargs. This helps with some instances of [point-free style](https://en.wikipedia.org/wiki/Tacit_programming).
1003
-
- If more positional args are still remaining when the top-level curry context exits, by default ``TypeError``is raised.
1001
+
- Passthrough for args/kwargs that are incompatible with the target function's call signature (à la Haskell; or [spicy](https://github.com/Technologicat/spicy) for Racket).
1002
+
- Here *incompatible* means too many positional args, or named args that have no corresponding parameter. (Note that if the function has a `**kwargs` parameter, then all named args are considered compatible, because it absorbs anything.)
1003
+
- Multiple return values (both positional and named) are denoted using `Values` (which see). A standard return value is considered to consist of one positional return value only.
1004
+
- Positional args are passed through **on the right**. Any positional return values of the curried function are prepended, on the left.
1005
+
- If the first positional return value of an intermediate result of a passthrough iscallable, it is (curried and) invoked on the remaining args and kwargs, after merging the rest of the return values into the args and kwargs. This helps with some instances of [point-free style](https://en.wikipedia.org/wiki/Tacit_programming).
1006
+
- If more args/kwargs are still remaining when the top-level curry context exits, by default ``TypeError``is raised.
1004
1007
- To override, set the dynvar ``curry_context``. It is a list representing the stack of currently active curry contexts. A context isanyobject, a human-readable label is fine. See below for an example.
1005
1008
- To set the dynvar, `from unpythonic import dyn`, and then `with dyn.let(curry_context=...):`.
1006
-
- Even with the upgrades in v0.15.0, passing through *named* args to an outer curry context isnot supported. This may or may not change in the future; fixing this requires support for named return values. See issue [#32](https://github.com/Technologicat/unpythonic/issues/32).
1007
1009
- Can be used both as a decorator andas a regular function.
1008
1010
- As a regular function, `curry` itself is curried à la Racket. If it gets extra arguments (beside the function ``f``), they are the first step. This helps eliminate many parentheses.
1009
-
-**Caution**: If the signature of ``f`` cannot be inspected, currying fails, raising ``ValueError``, like ``inspect.signature`` does. This may happen with builtins such as``list.append``, ``operator.add``, ``print``or``range``.
1011
+
-**Caution**: If the signature of ``f`` cannot be inspected, currying fails, raising ``ValueError``, like ``inspect.signature`` does. This may happen with builtins such as``list.append``, ``operator.add``, ``print``,or``range``, depending on which version of Python you have (and whether CPython or PyPy3).
1010
1012
-**Added in v0.15.0.**`partial`with run-time type checking, which helps a lot with fail-fast in code that uses partial application. This function type-checks arguments against type annotations, then delegates to `functools.partial`. Supports `unpythonic`'s `@generic` and `@typed` functions, too.
1011
1013
-`composel`, `composer`: both left-to-right and right-to-left function composition, to help readability.
1012
1014
- Any number of positional arguments is supported, with the same rules asin the pipe system. Multiple return values packed into a tuple are unpacked to the argument list of the next function in the chain.
The curried ``f`` uses up one argument (provided it is a one-argument function!), and the second argument is passed through on the right; this two-tuplethen ends up as the arguments to ``cons``.
1139
+
The curried ``f`` uses up one argument (provided it is a one-argument function!), and the second argument is passed through on the right; these two values then end up as the arguments to ``cons``.
1138
1140
1139
1141
Using a currying compose function (name suffixed with``c``), the inner curry can be dropped:
This isas close to ```(define (map f) (foldr (compose cons f) empty)``` (in``#lang`` [``spicy``](https://github.com/Technologicat/spicy)) as we're gonna get in Python.
1148
1150
1149
-
Notice how the last two versions accept multiple input iterables; this is thanks to currying ``f`` inside the composition. An element from each of the iterables is taken by the processing function ``f``. Being the last argument, ``acc``is passed through on the right. The output from the processing function - one new item -and``acc`` then become a two-tuple, passed into cons.
1151
+
Notice how the last two versions accept multiple input iterables; this is thanks to currying ``f`` inside the composition. An element from each of the iterables is taken by the processing function ``f``. Being the last argument, ``acc``is passed through on the right. The output from the processing function - one new item -and``acc`` then become two arguments, passed into cons.
1150
1152
1151
-
Finally, keep in mind this exercise is intended as a feature demonstration. In production code, the builtin ``map``is much better.
1153
+
Finally, keep in mind this exercise is intended as a feature demonstration. In production code, the builtin ``map``is much better. It produces a lazy iterable, and does not care which kind of actual data structure the items will be stored in (once computed).
1154
+
1155
+
The example we have here evaluates all items immediately, and specifically produces a linked list. It's just a nice example of function composition involving incompatible arities, thus demonstrating the kind of situation where the passthrough feature of `curry` is useful. It is taken from a paper by [John Hughes (1984)](https://www.cse.chalmers.se/~rjmh/Papers/whyfp.html).
1152
1156
1153
1157
1154
1158
#### ``curry`` and reduction rules
@@ -1172,15 +1176,20 @@ it means the following. Let ``m1`` and ``m2`` be the minimum and maximum positio
1172
1176
- If ``n < m1``, partially apply ``f`` to the given arguments, yielding a new function with smaller ``m1``, ``m2``. Then curry the result andreturn it.
1173
1177
- Internally we stack ``functools.partial`` applications, but there will be only one ``curried`` wrapper no matter how many invocations are used to build up arguments before ``f`` eventually gets called.
1174
1178
1175
-
As of v0.15.0, the actual algorithm by which `curry` decides what to do, in the presence of kwargsand`@generic` functions, is:
1179
+
As of v0.15.0, the actual algorithm by which `curry` decides what to do, in the presence of kwargs, `@generic` functions, and`Values` multiple-return-values, is:
1176
1180
1177
1181
- If `f`is**not**`@generic`or`@typed`:
1178
1182
- Compute parameter bindings of the args and kwargs collected so far, against the call signature of `f`.
1179
1183
- Note we keep track of which arguments were passed positionally and which by name. To avoid subtle errors, they are eventually passed to `f` the same way they were passed to `curry`. (Positional args are passed positionally, and kwargs are passed by name.)
1180
1184
- If there are no unbound parameters, and no args/kwargs are left over, we have an exact match. Call `f`andreturn its result, like a normal function call.
1181
1185
- Any sequence of curried calls that ends up binding all parameters of `f` triggers the call.
1182
1186
- As before, beware when working with variadic functions. Particularly, keep in mind that `*args` matches **zero or more** positional arguments (as the [Kleene star](https://en.wikipedia.org/wiki/Kleene_star)-ish notation indeed suggests).
1183
-
- If there are no unbound parameters, but there are args/kwargs left over, arrange passthrough for the leftover args/kwargs (that were rejected by the call signature of `f`), and call `f`. If the result is a callable, curry it, and recurse. Else form a tuple... (as above).
1187
+
- If there are no unbound parameters, but there are args/kwargs left over, arrange passthrough for the leftover args/kwargs (that were rejected by the call signature of `f`), and call `f`. Any leftover positional arguments are passed through **on the right**.
1188
+
- Merge the return value of `f`with the leftover args/kwargs, thus forming updated leftover args/kwargs.
1189
+
- If the return value of `f`is a `Values`: prepend positional return values into the leftover args (i.e. insert them **on the left**), and update the leftover kwargs with the named return values. (I.e. a key name conflict causes an overwrite in the leftover kwargs.)
1190
+
- Else: there is just one positional return value. Prepend it to the leftover args.
1191
+
- If the first positional return value is a callable: remove it from the leftover args, curry it, and recurse with the (updated) leftover args/kwargs.
1192
+
- Else: form a `Values`from the leftover args/kwargs, andreturn it. (This return goes to the next outer curry context, or at the top level, to the original caller.)
1184
1193
- If neither of the above match, we know there is at least one unbound parameter, i.e. we have a partial match. Keep currying.
1185
1194
- If `f`is`@generic`or`@typed`:
1186
1195
- Iterate over multimethods registered on `f`, **up to three times**.
0 commit comments