Earlier quoted context omitted.
I much prefer partial application. It just makes more intuitive sense - you take a function with many arguments, "fix" some of those arguments, and get a new function out. No need to mess with argument ordering, or all that. It's a shame the only language that did partial application well is, weirdly, Python.
In Gleam it also seems to be done well: https://tour.gleam.run/functions/function-captures/
Currying
121–130 of 134 posts
Re: Currying
#122Earlier quoted context omitted.
We can say that when a function is curried (i.e. prepared or converted to curried form) then it supports partial application without any further transformation. In fact it happens naturally whenever the function is invoked. E.g. if we have (lambda (x y z) (+ x y z)) converted into the curried form (lambda (x) (lambda (y) (lambda (z) (+ x y z)))), then while we do not yet have partial application, we can then partiall…
I think when calling a curried function it isn't easy to differentiate between a simple function application and a partial (function) application . I would make the assumption that as long as a higher-order function is called, then what we're actually doing is a function transformation and thus a partial application - when we applied all arguments except the last one, then finally, when the last argument of a first-o…
Re: Currying
#123Earlier quoted context omitted.
> I will get a type error and it will take me 2-3 seconds to figure out what it is about. You should really screen capture yourself coding sometime. On a large codebase you're lucky if the compiler even runs in 10 seconds. > Why would it be in a completely different part of the code? At most it would be 2 lines away, but usually on the same line. Because possibly you return the partial assuming it's a number, and try…
> Because possibly you return the partial assuming it's a number, and try to use it somewhere else, possibly even in another file. Sorry, I must've been more explicit instead of implying certain usage patterns. What I meant here is that I have a hard time imagining this happening because I would start working on a function by writing its type signature. Unless my types check out, I won't be able to mark this function…
I think writing out type signatures is The Right Way, but it does take time, and The Right Way doesn't always happen on complicated projects with close deadlines.
Re: Currying
#124Earlier quoted context omitted.
> It isn't true and i can understand why someone would make that statement It is true, and you are smart enough to understand it if you stop assuming you're the only one who understands the topic. I'm specifically sticking with the wording "Currying is a subset of partial application" to make the point that you can understand what someone is trying to say even if they don't say it exactly the way you would like them…
Neither of your examples does curry a function. The first one partially applies it (the Haskell way), the second one wraps the partial application in a redundant lambda (Haskell again). I think that's where the confusion is, let me also try to use the Haskell syntax... This is an add function with two arguments: add :: (Int, Int) -> Int add (x, y) = x + y At the moment it can not be partially applied, so let's curry…
Okay, writing this in Python because a) it's been a while since I wrote Haskell, b) it will let other readers read the code more easily, and c) Python clearly denotes what a partial is by having a `partial` function:
from inspect import signature
from functools import partial
def curry(f, parameters=None):
if parameters is None:
parameters = list(signature(f).parameters.keys())
if len(parameters) == 0:
return f
head = parameters[0]
tail = parameters[1:]
# I draw your attention to this line
return lambda p: curry(partial(f, **{head: p}), tail)
def divide(a, b, c):
return a / b / c
curried_divide = curry(divide)
# prints "3"
print(curried_divide(30)(5)(2)())
So... curry can be implemented in terms of partial applications, no?Re: Currying
#125Earlier quoted context omitted.
They say that array languages are pretty readable once you get used to them, too? But you’re drastically limiting your audience. Part of readability is writing for people who aren’t as fluent as you are. Expert jargon can sometimes be useful, but it often obscures things that would be pretty simple if written some other way. With Haskell there’s a tension between saying “I only care about writing for other expert pro…
It's not really saying "only expert programmers" though, is it? It's people who know Haskell, which by coincidence happens to be overzealous undergraduates and a certain subset of experienced programmers. FP is a paradigm among many, its basics somewhat predate (or since it's so close, co-date?) more imperative descriptions of computation. That we mostly use and as such mostly teach beginners with procedural language…
I write Python a great deal for a living these days and the Python code isn't much clearer to me. In both the Python and Haskell examples I can tell what it's doing (except the opaque neighbouringNumbers)--I just can't tell why it's doing it.
Re: Currying
#126I recently saw the title, Learn Physics with Functional Programming, and thought to myself... I know physics and functional programming but I want to learn Haskell. Having gone through it, I highly recommend the book; especially to anyone knowledgeable about any 2 and interested in the third. I love Haskell. I love writing it, and reading it. Haskell is a beautiful programming language. One where I felt immediately a…
Wow what a lot of parentheses! To me the first example is perfectly clear because it follows the same precedence rules I learned for arithmetic at school, along with most programming languages. There's nothing special about Haskell here, in Python I would write: >>> math.sqrt(2) + 1 * 3 + 3 * 2 + 1 / 7 10.557070705230238 The only difference I see is the parentheses used for function application in python.
Due to Haskell's rigor in regard negative numbers:
ghci> -1 + 2
1
ghci> 2 + -1
:12:1: error:
Precedence parsing error
cannot mix ‘+’ [infixl 6] and prefix `-' [infixl 6] in the same infix expression
ghci> 2 + (-1)
1
ghci> -1 * 3
-3
ghci> 3^-1
:3:2: error:
• Variable not in scope: (^-) :: t0 -> t1 -> t
• Perhaps you meant one of these:
‘^’ (imported from Prelude), ‘-’ (imported from Prelude),
‘^^’ (imported from Prelude)
ghci> 3^^-1
:4:2: error:
• Variable not in scope: (^^-) :: t0 -> t1 -> t
• Perhaps you meant ‘^^’ (imported from Prelude)
ghci> 3**-1
:5:2: error:
• Variable not in scope: (**-) :: t0 -> t1 -> t
• Perhaps you meant ‘**’ (imported from Prelude)
ghci> 3**(-1)
0.3333333333333333
ghci> sqrt 2 + 1 * 3 + 3 * 2 + 1 / 7
10.557070705230238
ghci> sqrt $ 2 + 1 * 3 + 3 * 2 + 1 / 7
3.3380918415851206
ghci> -sqrt 2 + 1 * 3 + 3 * 2 + 1 / 7
7.728643580484048
ghci> -sqrt $ 2 + 1 * 3 + 3 * 2 + 1 / 7
:25:1: error:
• Non type-variable argument in the constraint: Num (a -> a)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall {a}. (Floating a, Num (a -> a)) => a
ghci> sin -1
:7:1: error:
• Non type-variable argument in the constraint: Num (a -> a)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall {a}. (Floating a, Num (a -> a)) => a -> a
ghci> (sin -1)
:10:1: error:
• Non type-variable argument in the constraint: Num (a -> a)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall {a}. (Floating a, Num (a -> a)) => a -> a
ghci> sin (-1) -- -0.8414709848078965
Let's see, ghci> (sin (-1)) -- -0.8414709848078965
Ahh, now that's better.Re: Currying
#127Earlier quoted context omitted.
It's not really saying "only expert programmers" though, is it? It's people who know Haskell, which by coincidence happens to be overzealous undergraduates and a certain subset of experienced programmers. FP is a paradigm among many, its basics somewhat predate (or since it's so close, co-date?) more imperative descriptions of computation. That we mostly use and as such mostly teach beginners with procedural language…
It’s true that readability is culture-specific, that if the culture were different and people learned different things then different languages would be more readable. But I still think there are differences between languages in the sense of how much you can understand without knowing the definition of every term. For example, if you’re looking at Lisp code and you don’t know whether an outer term is a function, macr…
Yes, that's a problem.
There are two clues:
* Macros typically have naming conventions. For example anything beginning with DEF should be a defining macro, not a function. Anything with DO- will be a control structure. Anything with WITH- will be a scoping macro. And so on. Avoid active names like CREATE- and use DEFINE- instead. CREATE-CLASS would be a function, DEFINE-CLASS would be a macro.
* In source code the enclosed code typically has syntax and special indentation, when used with macros. Functions have certain uniform indentation rules.
(create-class 'container-ship
:superclasses '(ship)
:slots '((max-number-of-containers :type integer))
:documentation "our new container-ship class")
Above is a function and uses one of the typical formatting/indentation rules for functions. Line up the arguments. Start with the required argument and then the named argument pairs (name, arg).The macro looks different. The first important things like name and superclasses are on the first line. The other parts of the class specification follow and are indented by two characters.
(define-class container-ship (ship)
((max-number-of-containers :type integer))
(:documentation "our new container-ship class"))
Developers who write macros should make it clear what a macro is, by using hints like these.Re: Currying
#128Earlier quoted context omitted.
> no one in this comment chain is confused about what currying or partial application are I can't agree here either... I know it from my own experience when i first learned about currying and partial application.
It does not appear to me that skybrian is first learning about currying and partial application, and I'm not first learning about currying or partial application in this thread either. Your play at humility that you didn't understand currying and partial application in the past kinda falls flat if you then go on to less-humbly assume that everyone else in the conversation is stuck where you once were.
I understood it instead to be generalizing to a related concept, and inferred no condescension, FWIW.
Re: Currying
#129Reading through these comments, it's clear that currying isn't clearly understood, which makes me doubt it's worth the cognitive load to use in a codebase.