About documentation, immutability, first-class functions and dynamic and static environments
One of the most important things I’ve learned during the Programming Languages Part A course is the idea of dynamic and static environments. Considering I’ve never seen this explained anywhere else so far, I’ll try my best to explain this.
let x = 5
/*
static: x: int
dynamic: x = 5
"At this point, there's an x of type int and the value of x is 5"
*/
let y = 10
/*
static: x: int, y:int
dynamic: x = 5, y = 10
"We now have both x and y with their corresponding types and values in the environments
*/
let addX = (num) => num + x
/*
static: x: int, y: int, addX: int -> int
dynamic: x = 5, y = 10, addX = fun
"Introducing functions as value as any other that gets put inside the dynamic environment
with all other values makes it clear we can pass functions around as arguments.
What also happened is that the function addX "takes" this current environment with it
whenever it will be used. Example of this will come later
*/
let x = "whatever"
/*
static: x: string, y: int, addX: int -> int
dynamic: x = "whatever", y = 10, addX = fun
Now it's clear what "shadowing" actually means.
We're creating new static and dynamic environments after every binding,
so the type and value of x at inside the environments at this point of the program is different
*/
let z = addX(50)
/*
static: x: string, y: int, z: int, addX: int -> int
dynamic: x = "whatever", y = 10, z = 55, addX = fun
This is the important part. Because in the environment in which addX was defined x = 5,
this function still adds 5 to its argument
*/
let list = List.map(~f:addX [1,2,3,4,5])
/*
static: ...everything else, list: list(int)
dynamic: ...everything else, list = [6,7,8,9,10]
I think this now makes complete sense. We could pass the function addX to List.map
because it's a value and it added 5 to every element of the list, because in the environment
in which it was defined x = 5
*/
Now that I think of any ML program as this series of static and dynamic environments, immutability also makes perfect sense. Of course you can’t change a value of a variable, you’re creating new environments after every binding.
The problem is immutability is rarely explained any further than “you can’t change the values of variables”. But if I saw this example from Exploring ReasonML just a couple months ago, that would be utterly confusing to me. What ARE we doing then?
# let x = 1;
let x: int = 1;
# x;
- : int = 1
# let x = 2;
let x: int = 2;
# x;
- : int = 2
The official documentation isn’t much better
let message = "hello";
print_endline(message); /* Prints "hello" */
let message = "bye";
print_endline(message); /* Prints "bye" */
Didn’t we mutate the value? Technically we didn’t, but it certainly looks like we did. The problem is it’s never actually explained why this isn’t mutation.
There’s many more places in the documentation and other explanation of ReasonML (and other Functional Programming concept in general) with which I have issues. I’ve mentioned Destructuring on Discord already, which is something that’s made up for the JavaScript developers, but in reality isn’t actually a thing. It’s pattern-matching. Technically, even a let binding is pattern-matching. And as I also said on Discord, I totally understand why it’s explained that way.
I understand it’s trying to simplify things for JavaScript developers. The truth is I’m a beginner JavaScript developer and I don’t understand 95% of ReasonML. I believe the problem is with how it’s explained and the documentation structured rather than it being difficult. What made me understand things are these very fundamental concepts that I learned about from somewhere else. That even includes the basics of lambda calculus.
My point
I wasn’t sure where I was going with this actually…
I guess I want ReasonML to succeed as much as all of you probably do, but I believe the approach to teaching it needs to be fundamentally different. I don’t think the official documentation can start with lambda calculus, so I want to make something of my own.
I’ve already had some ideas of how to explain what I just did semi-interactively rather than writing or making videos about them. The problem is that I will need a lot of help with things. I’ll try to make the semi-interactive version of what I explained above. If there’s someone who understands ReasonML deeply and would be willing to help me, then please let me know.
Mostly I just want to start a bit of a discussion around this. What do you think?