4 ms·
Ok, you're probably proving the point that purity also requires immutability. I'm not sure, as I haven't considered all the implications of Haskell's design. M
by elbear 2y ago
Ok, you're probably proving the point that purity also requires immutability. I'm not sure, as I haven't considered all the implications of Haskell's design.
My two rules about inputs and outputs are more like heuristics. They can improve code organisation and probably also decrease the likelihood of some errors, but they don't guarantee correctness, as you're pointing out. They're shortcuts, so they're not perfect.
Edit: If I remember right, it's laziness that requires immutability. I think I read something about this in the Haskell subreddit as an explanation for Haskell's design.
- Dylan16807 2y agoEven without laziness, you can get similar problems if f creates a closure or returns something that includes the parameter object.
- trealira 2y agoYeah, this is a common source of confusion with closures in Python. Example on Stack Overflow: https://stackoverflow.com/questions/233673/how-do-lexical-closures-work https://stackoverflow.com/questions/233673/how-do-lexical-cl...
- elbear 2y agoDoesn't that example also show a kind of laziness? I say this because the second solution to that question offers the solution of using `i` as a default argument when defining the function. That forces its evaluation and fixes the problem.
- trealira 2y agoIt's just a name shadowing. Copying the code they wrote: for i in xrange(3): def func(x, i=i): # the *value* of i is copied in func() environment return x * i flist.append(func) That could also be written "def func(x, foo=i): return x * foo". It's just copying i's value to another variable. In the next line, i's value is still 1, 2, or 3, so when the function is called during the next line of the body of the loop, the value held by i is bound to foo. It's not evaluating a thunk representing i, which is how lazy variables are evaluated in Haskell.
- elbear 2y agoOk, I had a better look at the code and I realised that it doesn't follow the rule I was talking about, namely having the function only work on values it receives as inputs. I think that's why I don't use closures, because they read values from the environment. Their only use case (that comes to mind) can be solved with partial application, which is safer. Oh, and I wasn't using laziness in the Haskell sense, but more in the general sense of deferring evaluation.
- elbear 2y agoOk, the Wikipedia definition of pure function is more strict and than what I was saying and I think it covers the issues you mentioned: https://en.wikipedia.org/wiki/Pure_function https://en.wikipedia.org/wiki/Pure_function