Earlier quoted context omitted.
Callbacks are not the same as monads if that is what you are implying.
That's right, but only because it's a 1-to-many comparison error. Callbacks are one particular monad, not monads in general: https://jsdw.me/posts/haskell-cont-monad/
What's functional programming all about? (2017)
141–150 of 158 posts
Re: What's functional programming all about? (2017)
#142Earlier quoted context omitted.
No. You missed it the meaning. The paradigm is referring to the fact that the ENTIRE program must be constructed this way. So let's say you have this in your code: x = 1 b = x + 2 x = b + x You have composed three procedures here in order. This is illegal. You must ONLY construct the programs via composing functions there can be no other way.
Not so fast. This next is legal Haskell: let x = 1 b = x + 2 x = b + x in The third line creates a second binding of x which shadows the first binding, and shadowing is considered by most people to be within the functional paradigm. What is not considered functional by most people is assigning a variable in a loop although even here you can do it in Haskell. Specifically, you can call readIORef and writeIORef every l…
Re: What's functional programming all about? (2017)
#143Earlier quoted context omitted.
That's right, but only because it's a 1-to-many comparison error. Callbacks are one particular monad, not monads in general: https://jsdw.me/posts/haskell-cont-monad/
Promises in JavaScript are not monads as far as I can tell. While they have a somewhat similar interface, they do not appear to obey the monad laws.
Re: What's functional programming all about? (2017)
#144Earlier quoted context omitted.
I also come from the Haskell corner and I agree with roenxi. I don't think that FP is a well-defined concept, nor do I understand your characterization of pure FP. Let's take a simple program main = do v and have a look at the conditions you laid out * Are you writing a procedure that just processes its arguments into a return value? No, it has no arguments and its return value is just (), but it does more besides. *…
main is never pure. Your `procedure` is also not pure (and also not referentially transparent). You can write impure code in Haskell, which your example demonstrates very well. But then it is necessarily IO code. Non-IO code, on the other hand, is always pure (and referentially transparent). > but I don't see that that changes anything It changes everything, but I can't explain it any better than I did above. > So wh…
Ah, it's possible I misunderstood you. I missed that you said "Purely functional languages force you to program this way by default". I mistakenly assumed you were saying that in a purely functional language you can only program purely.
So you are saying that Haskell is a pure functional language, but you can also write non-pure things in it? So being a "pure language" is more a case of what sort of style is encouraged rather than what sort of style is possible?
> (and also not referentially transparent)
Interesting. Could you explain what you mean by that? (The definition of referential transparency that I know doesn't apply to functions but to languages.)
> You can write impure code in Haskell, which your example demonstrates very well. But then it is necessarily IO code. Non-IO code, on the other hand, is always pure (and referentially transparent).
That's interesting. How do you distinguish these two pieces of code:
f = do
v
is the former impure and the latter pure? Or are both impure?> So what is it that makes Haskell a pure functional language and Python not?
If you give me a Haskell procedure `f1 :: Int -> Int` without showing me the content, I still know that it is referentially transparent and pure ... In Python, these conclusions would be invalid from the start.
Do you mean because of the type? If not, I don't understand what distinction you're drawing, and what makes the conclusions invalid for Python. If so, then does a pure language have to be typed? Would it be impossible for a pure language to be untyped?
> Now you can say, “So what? Who cares?” But it helps me enormously when designing and structuring programs, understanding programs, localizing program behavior, etc. If you don't see any added value in this distinction (ensured by the compiler), we don't have to argue about it.
We don't have to argue about it. I program in Haskell every day and reap the benefits :)
> But I simply cannot agree with you that this does not represent a conceptual and formally justified difference between Haskell and Python.
I agree there's a conceptual and formally justified difference between Haskell and Python. I just don't agree with you about how to characterize it :)
To reiterate my characterization, it is that Haskell has "referential transparency", that is
let x = rhs in ... x ... x ...
has the same result as ... rhs ... rhs ...
regardless of how many times (or zero) x occurs. That's it! Nothing to do with "purity", "IO", "processing arguments", "non-static contexts" or "side effects". Now I may be wrong. That's why I'm trying to understand what you think the characterization is.But so far I have never discovered a benefit of programming "purely" in Haskell that is not ultimately a consequence of what I call "referential transparency" above. Do you know one?
Re: What's functional programming all about? (2017)
#145Earlier quoted context omitted.
Promises in JavaScript are not monads as far as I can tell. While they have a somewhat similar interface, they do not appear to obey the monad laws.
There is one particular edge case in which they do not satisfy the laws. That happens to make them much more practical in day to day coding than a strict interpretation would be.
It seems to confirm the argument that monads are not that useful or pervasive outside of Haskell.
Re: What's functional programming all about? (2017)
#146Earlier quoted context omitted.
Here's a good enough definition: "The same input yields the same output". > "functional programming is a programming paradigm where programs are constructed by applying and composing functions" This is only seems like a useless truism if you take 'function' to mean 'method' or 'procedure'. If you nail down 'function' to sameinput->sameoutput then it starts to make more sense.
No. You missed it the meaning. The paradigm is referring to the fact that the ENTIRE program must be constructed this way. So let's say you have this in your code: x = 1 b = x + 2 x = b + x You have composed three procedures here in order. This is illegal. You must ONLY construct the programs via composing functions there can be no other way.
And good riddance, too! I'm so sick of seeing this anti-pattern at $DAYJOB: First, create a thing which isn't what you called it (e.g. 'result'), and then mutate it in place until it is what you called it.
Re: What's functional programming all about? (2017)
#147Earlier quoted context omitted.
Conspicuously absent in that thought is an alternative way to interpret "is based on". Because I suspect that in most senses that FP is based on lambda calculus we probably can claim it is also based on a subset of Java. Everything useful is multi-paradigm these days, programming paradigms turned out to not be a useful lens for developing useful programming languages.
> Conspicuously absent in that thought is an alternative way to interpret "is based on". "Has designers who consciously adopted significant ideas from" seems good enough for me.
Indeed, the definition admits that we could have two almost identical languages but only one of them is based on lambda calculus. I don't think it is a reasonable way to interpret "is based on", it requires too much knowledge of history. It is more proper to have a technical definition that is rooted in the language itself.
Re: What's functional programming all about? (2017)
#148Earlier quoted context omitted.
There is one particular edge case in which they do not satisfy the laws. That happens to make them much more practical in day to day coding than a strict interpretation would be.
So having Promises be monads would make them less useful? This is an interesting point. It seems to confirm the argument that monads are not that useful or pervasive outside of Haskell.
Re: What's functional programming all about? (2017)
#149Earlier quoted context omitted.
So having Promises be monads would make them less useful? This is an interesting point. It seems to confirm the argument that monads are not that useful or pervasive outside of Haskell.
We might consider promises “applied monads” or “engineered monads”. Monodic in inspiration and they solve the same core problem, but they aren’t straightjacketed into the ivory tower “laws” in absolutely every edge case (they do satisfy them in the vast majority of cases). Which is good, because it means we never need to write things like “await await await await await foo()”
Re: What's functional programming all about? (2017)
#150Earlier quoted context omitted.
main is never pure. Your `procedure` is also not pure (and also not referentially transparent). You can write impure code in Haskell, which your example demonstrates very well. But then it is necessarily IO code. Non-IO code, on the other hand, is always pure (and referentially transparent). > but I don't see that that changes anything It changes everything, but I can't explain it any better than I did above. > So wh…
> main is never pure. Your `procedure` is also not pure Ah, it's possible I misunderstood you. I missed that you said "Purely functional languages force you to program this way by default". I mistakenly assumed you were saying that in a purely functional language you can only program purely. So you are saying that Haskell is a pure functional language, but you can also write non-pure things in it? So being a "pure la…
> So being a "pure language" is more a case of what sort of style is encouraged rather than what sort of style is possible?
The crucial point is that the (potentially) impure code is clearly and explicitly differentiated from pure code (IO code vs. non-IO code. Haskell uses the type system to draw this distinction.
>> (and also not referentially transparent)
> Could you explain what you mean by that? (The definition of referential transparency that I know doesn't apply to functions but to languages.)
Functions are expressions in Haskell (and in Python). Applications of functions to their arguments are also expressions. I use "procedure" as a synonym for "function".
As I understand it, referential transparency is a property of expressions. But if we understand a language as the total set of expressions that result from its alphabet and its production rules, then we can say that a language is referentially transparent if and only if all its expressions are referentially transparent. Consequently, the views are compatible.
An expression is referentially transparent if it can be replaced by its value (what the expression evaluates to) without changing the behavior of the program.
This implies that if side effects are emitted during the evaluation of an expression, then the expression cannot be be referentially transparent, because these side effects would disappear if the expression is simply replaced by its value in the program. If a dynamic (i.e. changeable) context is also processed during the evaluation of an expression, then the expression cannot be guaranteed to be referentially transparent over time either.
A function (i.e. procedure) is pure if it (1.) always returns the same return value for the same arguments and (2.) does not produce any side effects. Note that the definition is also compatible with functions that do not process arguments. The requirement is the same: the same return value must always be returned.
This implies that a function is pure if the relation between its arguments (even if they are 0 arguments) and its return value is like that of a mathematical function. I already wrote that above. It simply boils down to the fact that you can execute the function as many times as you want: it will always return the same value (for the same arguments). This is only guaranteed if the function does not operate on a dynamic context in addition to its arguments (including system time, values from a random generator, etc.). Pure functions are just stupid simple things that deterministically transform their arguments into some value. I want these things to make up as much of my code as possible, because they combine like Lego and are pretty foolproof to handle. The value proposition of purely functional programming languages is that they semantically distinguish these pure functions from impure functions. In Haskell, I only have to look at the type of a function. If it is something like `t1 -> t2 -> ... -> IO tn`, then the function is potentially impure because it evaluates to a value that is wrapped in the IO monad, so to speak. For any other function in Haskell, I know for sure that it is pure. So I can write as much pure code as possible and then add a bit of IO code to interface the pure code with the execution context, or with other subsystems of the program where it is unavoidable to work with shared state. I can also do all that in Python. But in Haskell, the language semantics ensure that my code intended to be pure is really pure, and recognizably different from impure code.
To answer your question: purity implies referential transparency. I can understand that from the definitions. Conversely, the implication does not apply. I don't understand exactly why, but so far it hasn't been a priority for me to understand this.
> is the former impure and the latter pure?
Correct. You can recognize this by the data types:
f :: IO Integer
g :: GHC.ST.ST s Integer
You use do notation in both cases, but that has nothing to do with it. You can write not only IO code with the do notation, but all kinds of other code.
foo :: String
foo = do
s
The do notation is only syntax to avoid the bind operator. Otherwise your functions would look like this:f :: IO Integer
f =
newIORef 0 >>= \ v ->
modifyIORef v (+1) >>
readIORef v
g :: GHC.ST.ST s Integerg =
newSTRef 0 >>= \ v ->
modifySTRef v (+1) >>
readSTRef v
> ...> Do you mean because of the type?
Exactly. I can see from the data type that f1 is pure and f2 is impure.
> what makes the conclusions invalid for Python.
Consider this code:
def add(a: int, b: int) -> int:
print("hello")
return a + b;
The function is impure because of the print. Without the print, it would be pure. But the type annotation would be exactly the same. The example is a bit silly, because the type annotations are not taken into account in Python anyway (unless you use typeguard)In Haskell you cannot simply print something in a procedure of type `Int -> Int -> Int`. The type checker would reject it. If you want to do that, you have to type it as `Int -> Int -> IO Int`. You can then no longer simply use it as if it were typed as `Int -> Int -> Int`. It is then simply a completely different procedure: an impure one.
> does a pure language have to be [statically] typed?
Very good question! I don't know. I don't think it's formally a requirement, but I only know languages that handle it via the type system (IO, algebraic effect handlers, TEA).
> But so far I have never discovered a benefit of programming "purely" in Haskell that is not ultimately a consequence of what I call "referential transparency" above. Do you know one?
I think you're right about that. Purity and referential transparency somehow seem to be almost the same thing but not 100% congruent. I have a gap in my understanding at this point.
https://stackoverflow.com/questions/4865616/purity-vs-refere...
This seems to suggest that I won't be able to close this gap any time soon. In the end, it probably doesn't matter. I assume we both mean the same thing.