8,134 karma · joined May 1, 2010
https://twitter.com/jasim_ab
jasim.ab@gmail.com
However, one of the better things about Reason for me is that it is based on OCaml, which has been a rock-solid language for more than two decades. Its pace of evolution is quite measured - for example the algebraic effects work that has been happening is based on a formal academic foundation, and the implementation is often lead by researchers who wrote the actual papers.
The biggest issue I can imagine when a company adopts Reason is availability of bindings to Javascript libraries. In practice this has not been much an issue for me - once you get grips with the way bindings are done in BuckleScript, creating a binding is just another thing to do.
The other issue is significant upfront learning cost for the Typed functional paradigm. But it is the kind of fundamental learning that pays dividend for a long time, quite unlike learning libraries or frameworks that simply keep coming and going.
I find that Reason and Elm does solve for this constant library/framework trivia-treadmill of the Javascript ecosystem admirably, helping teams achieve enough technical expertise so they can effectively create most of the building blocks they need by themselves.
Similarly I thought all of Lex's questions came from deep understanding of what he was asking, and he would've known clearly what Sanderson would've replied (minus his personal insights) and what other competing answers are out there.
I love Lex Friedman's interviews - he simply asks a small but fertile question and then lets the guest talk.
1) An object is a poor man's closure; and a closure is a poor man's object.
2) Most object-oriented programming is done with mutable state, which muddles what OO is. You don't really need state to have objects.
In a closure, the lexical scope is preserved, and the functions defined in it can access it any time. This is very similar to what an object does: https://stackoverflow.com/a/2498010
When objects are immutable, one gets to truly appreciate the elegance of grouping both data and their functions together: https://dev.realworldocaml.org/objects.html#scrollNav-3
* Use a statically typed language that allows fast refactoring. Ideally a typed functional language like Elm, Reason, OCaml, or Haskell.
I recently shipped a complex Javascript project (without types) and it is one of the few instances of my decade-old professional career where I had that level of confidence in the robustness of a piece of code I wrote. It remained sturdy in production even in the presence of unforeseen conditions. This was thanks to the habits I picked up from typed FP: parsing and validating all data at the boundaries of the system, better design by modelling data to make inconsistent states impossible, and automatically handling all edge-cases at all times.
So even if you don't actively use such a language in your workplace, there really is a payoff to learning it in making you a better programmer overall.
Daniel Waterhouse: 'Sir! You show me a few gears that add and multiply numbers – well enough. But this is not the same as thought !'
'What is a number, Mr. Waterhouse?'
Daniel groaned. 'How can you ask such questions?'
'How can you not ask them, sir? You are a philosopher, are you not?'
'A Natural Philosopher.'
'Then you must agree that in the modern world, mathematicks is at the heart of Natural Philosophy – it is like the mysterious essence in the core of the snowflake. When I was fifteen years old, Mr. Waterhouse, I was wandering in the Rosenthal – which is a garden on the edge of Leipzig – when I decided that in order to be a Natural Philosopher I would have to put aside the old doctrine of substantial forms and instead rely upon Mechanism to explain the world. This led me inevitably to mathematicks.'
'When I was fifteen, I was handing out Phanatiqual libels just down the street from here, and dodging the Watch – but in time, Doctor, as Newton and I studied Descartes at Cambridge, I came to share your view concerning the supreme position of mathematics.'
'Then I repeat my question: What is a number? And what is it to multiply two numbers?'
'Whatever it is, Doctor, it is different from thinking .'
'Bacon said, ‘Whatever has sufficient differences, perceptible by the sense, is in nature competent to express cogitations.' You cannot deny that numbers are in that sense competent – '
'To express cogitation, yes! But to express cogitations is not to perform them, or else quills and printing-presses would write poetry by themselves.'
'Can your mind manipulate this spoon directly?' Leibniz said, holding up a silver spoon, and then setting it down on the table between them.
'Not without my hands.'
'So, when you think about the spoon, is your mind manipulating the spoon?'
'No. The spoon is unaffected, no matter what I think about it.'
'Because our minds cannot manipulate physical objects – cup, saucer, spoon – instead they manipulate symbols of them, which are stored in the mind.'
'I will accept that.'
'Now, you yourself helped Lord Chester devise the Philosophical Language, whose chief virtue is that it assigns all things in the world positions in certain tables – positions that can be encoded by numbers.'
'Again, I agree that numbers can express cogitations, through a sort of encryption. But performing cogitations is another matter entirely!'
'Why? We add, subtract, and multiply numbers.'
'Suppose the number three represents a chicken, and the number twelve the Rings of Saturn – what then is three times twelve?'
'Well, you can't just do it at random, ' Leibniz said, 'any more than Euclid could draw lines and circles at random, and come up with theorems. There has to be a formal system of rules, according to which the numbers are combined.'
'And you propose building a machine to do this?'
'Pourquoi non? With the aid of a machine, truth can be grasped as if pictured on paper.'
-- Quicksilver, Baroque Cycle (#1), Neal Stephenson
But Harbour, an open-source implementation of Clipper superseded it with Metaphone - https://harbour.github.io/doc/hbnf.html#ft_metaph
But most transactional systems where things move from one entity to another and has the notion of "balance value" is best represented by the double-entry system.
When a customer purchases pre-paid balance, the phone company can record it as a "credit", and every call they make becomes a "debit". This is an immutable log - one of the earliest application of immutable data structures in human history.
In this post authors used positive and negative values to represent debit and credit - we could call it yin and yang for all it mattered. The core principle is just that every transaction has a source and destination and the ledger is an append-only table.
You have a lot of flexibility in choosing the width and height of each cell, but they are rigid.
In case of Flexbox, we don't specify any fixed lines to which the elements will size. Instead, we say general rules saying elements can grow to as much size is available, or stay at the beginning of the row etc. The layout is determined to a large extend by the elements we place rather than on a fixed set of gridlines.
For people from dynamically typed or static OO background, being able to write functional code with records and sum types alone is a huge quality of life improvement. They should be able to get there with the least amount of effort. Haskell however demands far too much understanding and effort before it can be confidently used in a commercial setting. That excludes mainstream programmers who could otherwise most benefit from the paradigm.
It is only recently that I've started getting comfortable with concepts cogently explained in this post, so to me it is quite valuable.
As an aside, I think OCaml/Reason/Elm should become the de-facto Typed FP entrypoint for programmers instead of Haskell. That'll help drive more adoption for the paradigm because the ecosystem is a lot more approachable and one wouldn't feel overwhelmed to even begin.
In OCaml, (List.hd []) throws an exception, which is not a desirably behaviour, so we mostly use a safer version of List.hd which would return an option type. This could be either "None" or "Some(value)". To operate on option types, we have to pattern match and handle both cases where the value could be either None or Some)
Exhaustive pattern matching is useful here, so is the very notion of variants. Without variants (or sum type / union type) we tend to leave domain concepts implicit in the codebase. While we can simulate variants with classes, it is too unwieldy to be used except for core domain concepts.
A common clerical mistake which Elm, Reason etc. prevents, is when we grab something from a list and pass it to another function. What if in a rare case it is possible that the element doesn't exist? A function deeper in the stack might crash, or if defensively built, substitute it with an empty value. Both could be wrong.
By providing more information about our data and our functions to the compiler, the compiler can ensure our code always follow those constraints. These constraints are often in our head when using dynamically typed languages, or even statically typed OO languages. Typed FP helps us make them explicit in code so the compiler can track it instead of we tiring ourselves mentally and making a mess of it.
-- Unseen Academicals, Terry Pratchett
Often people seem to use ideas in Factfulness (Rosling) to assuage the guilt of living well and free when there is suffering all around. This is fine, but this also seem to give ammunition to others who argue that people's fates are in their hands alone, minimum wages should be abolished, and being a rickshaw driver is fine - because they need jobs, and it is as good a job as any for people "like them". The reasoning from "things are improving" to "society don't owe individuals succor" seem to be illogical, but reoccuring nonetheless.
Regarding bindings -- which external libraries were you using? Component libraries written for React could be a fair amount of work to write bindings for, but I anyway prefer hand-rolling components with Tailwind, so that hasn't been a problem personally.
Bindings were indeed difficult when I started out - Javascript can invoke functions in a myriad ways: new xyz(), object.key, object.key(), module defaults, Math.abs etc. We have to map them to OCaml's semantics (easy), and figure out the BuckleScript macros for them (easy with practice). I recently wrote a bunch of bindings for Adobe XD, and it was surprisingly fun.
What I'm extrapolating from this is that McCarthy's ideas are similar in implication to Lambda Calculus where you can define computation with just function abstraction and application, and use Peano numbers to represent data. Both approaches end up creating a purely functional way to write programs.
Would that be correct? I also wonder whether there is anything we can take away from this knowledge that is applicable to programming or how we look at it?
If you want to change density of the design, you can change the spacings centrally in the configuration itself. But if you need a non-proportional change, then it isn't any different than BEM+SASS environment where you'd have to go into every CSS class and make the change. I think it is even better than BEM here because you only need to change classnames in HTML, which is co-located with the style, and it doesn't cause cascading changes due to specificity etc.
To me the opinions you hold seem to come from not having tried it in good faith, which was how I used to judge functional CSS as well. If the current CSS style you use serves you well, that's fine you don't have to explore. But if you've wondered whether there is something wrong with the way we do CSS today, then Tailwind could be an eye-opener.
If you treat it as a programming problem, you can write better front-end code by shoring up on your ability to compose, glue, and modularize code. You also need a way to represent front-ends as a data structure rather than a sequence of imperative actions. Data is easier to think about - imagine if instead of HTML you had to write imperative code to paint everything on the screen - that kind of code can get tangled up easily and make it difficult to understand or modularize the code.
In this vein, using a library that lets you think of the front-end as data ('declarative') rather than imperative DOM mutation (with jQuery etc.) is an important thinking tool.
A way to short-circuit the amount of learning associated with this is to pick-up tools that have already reified this knowledge, so that by learning the tool you pick up the many mental models they embody. I suggest either Reason (with ReasonReact) or Elm as great starting point. Pursue their homepages, toss a coin, pick the one that appeals to you on first blush.
Both these languages are typed functional languages. Types here are tools of thought - especially the ability to represent data as One of Many (sum types) - will forever add a dimension to the way you model data. Functional programming is a toolkit of methods that let you compose and glue code together, and while it wouldn't appear that they attack the problems you're facing head on (should I add yet another conditional here, or should I extract another function that looks almost the same vs DRY etc.), those are exactly the problems you'll be able to confidently answer after you've practiced in this paradigm for a while.
The best trade-off I've found is to give a unique CSS classname for the container which has user-generated content, and then style it using nested selectors. Here you can use Tailwind's @apply so you're still able to rely on Tailwind's design system.
It is very liberating to use Tailwind instead of creating unique CSS classes for every div in a page. The code is much more maintainable - in a single stroke Tailwind gets rid of selector specificity issues, design inconsistency, and naming woes.
From a programming perspective, the conventional style of "semantic" CSS classes creates deep and fragile coupling between markup and CSS. It goes against everything good code is supposed to be - when you change the structure of the HTML you're forced to change the CSS, and if you truly use the power of CSS selectors, then modifying CSS becomes a difficult enterprise: one change can create multiple unrelated changes at a distance.
Tailwind solves all this, with just two downsides: until you spend a few hours mucking with it, the markup look will look unwieldy, and you have to be ready to really think about semantic CSS and "separation of concerns" dogma we've taken for granted for so long.