The red book is for you
If you want something that's easy to start with I'd recommend Atom with parinfer and protorepl. Personally, I use Cursive and it works pretty well in my experience. It's got a lot of nice features like refactoring, jumping to definition, hinting invalid arguments, unused function detection, and so on.
If it isn't for something serious, but just for learning, then you could go with elm. I made this little snake clone with it once and I'm currently using it for a small infinite runner game. It is very enjoyable to work with, but elm isn't at its best when used for a game.
If you wanna make a real game, go with libgdx/unity/unreal etc.
If you're doing backend work I highly recommend hyper-ts, it's a great way to plug in verification and keeps a consistent fp style interface. I struggled to make express middleware work well with io-ts
From the ones you list, I believe Elm is the best option to learn FP and is quite easy to get started because more abstract constructs that you'll encounter in Scala or Haskell are not available there, but other than for learning FP I think it is not a good choice, I wouldn't even recommend it for frontend web development (better PureScript or ReasonML for that).
From these 3, I prefer Clojure, I've used Clojurescript for some hobby projects and I like it a lot, but I don't really know how it fits in IoT, perhaps if you use some of those tools that run javascript in constrained devices then you could use Clojurescript instead. Besides that, you could use Clojure for any other kind of application, web development, mobile app development, backend, etc.
Last, Elixir has native support for building fault-tolerant distributed systems and that seems to fit IoT quite nice (I suppose I'm not well versed in IoT). Other than that I don't have anything much to say about it, I find it quite nice for web development but I believe even for that I like Clojure more.
You may also consider Haskell just for the learning FP aspect, and then transition into Rust since its a language that gets you close to the metal, basically a safer C. Embedded devices it's one of its strongest selling points.
There are plenty of GUI libraries out there for languages such as Haskell. In general, however, functional languages are a bit cumbersome to use for real-time or interactive systems.
You might be interested in looking into functional reactive programming, which has recently been gaining some popularity. FRP captures the concept of data as a function of time very elegantly, all within a functional style. Check out http://elm-lang.org.
What you've been asked to do is not really great. In fact, it's pretty bad.
The best thing about it is getting rid of loops. Loops are error-prone (fenceposts, which I still usually get wrong the first time). They also disrupt a declarative programming style, although that hardly matters if everything else isn't declarative already. Pattern matching, on the other hand, is hands down my favorite language feature anywhere.
But as soon as one starts programming functionally, one should take advantage of functional combinators. I.e., functions that operate on other functions. You are creating one in this snippet, but the example given is splicing together everything itself in the body. Instead, you could be using more general combinators. In psuedocode, I would write:
function createStuff(createFunction, howManyTimes){ return enumFromTo(0,howManyTimes).map(createFunction); }
As you can see, this is so simple that it shouldn't even be wrapped into "createStuff". Just use map directly.
The reason this is pseudocode is that JavaScript doesn't have a nice way to
create arrays (like Haskell's [0..howManyTimes]
). You could use
underscore.js' times though, or create
your own utility function. It would be a low-level function that does use
a loop, but you'd only have to get the fenceposts right once and never
worry about it again. :)
Maybe you could take a look at Kotlin? Maybe not as singularly focused on FP as Clojure, but it has a large FP influence. Also it compiles to JS.
You've already listed quite a few options to do web tech + backend a la electron.
Tauri is another interesting option. E.g. here's an article on using Tauri together with Elm: https://dev.to/jxxcarlson/making-an-elm-desktop-app-with-tauri-3n3i
I'm with you, there.
C++ has Boost's multi_index that lets you create a lightweight datastructure that will manage the indexes that you declare for you.
I've yet to see the essence of that library ported to other languages I've used.
Just seems like a lack-of-library problem. I've used an in-memory SQL database to replicate this, but it's obviously a heavier solution than what a multi_index library would be able to offer, though it's general.
I've also implemented my own ad-hoc functions that manage multiple indexes for me. But I guess you're asking how to generalize it, and that's not trivial no matter what language you're using.
For example, it's obvious how to modify my push
function so that it updates separate byFirstLetter, byLastLetter, byLength indexes incrementally.
just catching this post! I've been a Javascript developer for a long time and just getting into the functional approach to things. this question is something I'm struggling with too and I've come to the conclusion that you don't need to trap yourself in that mindset.
code needs to change something, otherwise it exists for no reason. so rather than focusing on making every function pure, the better approach is to think about how you can separate the logic that modifies something (imperative) from the logic that exists as a flow of pure data morphism.
ultimately manipulating the dom, or writing to a file, will never be pure.
I think the best thing to do is just dive right in and learn as you go. I have learned a lot from this series of videos where the creator of cycle.js walks through the creation of his framework:
https://egghead.io/lessons/rxjs-the-cycle-js-principle-separating-logic-from-effects
Yeah it kind of surprised everyone. I follow /r/ocaml and /r/reasonml so I caught the initial rebranding and subsequent confusion, and it was a mess. At first it sounded like Reason and BuckleScript decided to merge and drop OCaml support, especially since a lot of us thought the reasonml.org site was the official entry point to Reason since it presented itself as such. Then it became clear that Reason wasn't going anywhere and this was a move by BuckleScript and a subset of the Reason community that only cared about the JS side to abandon Reason and OCaml, and the Reason side as just as surprised by the move.
Now the real Reason site primarily mentions using js_of_ocaml for JS compilation instead of endorsing bucklescript, though maybe when Melange's changes and updates* to bucklescript stabilise it'll switch over to suggesting that. jsoo is good at what it does but it uses some OCaml black magic that creates some awful error messages; plus it converts the intermediate AST representation to JS and creates a giant unreadable blob. BuckleScript (and now Melange) take over compilation a bit earlier, giving you more readable output and allowing some things to be done more smoothly.
* BuckleScript/ReScript works by forking the OCaml compiler and has been stuck on years-out-of-date versions of it as a result. Works well but you miss out on some nice stuff that's been done the past few years. Melange is trying to fix some of that by splitting out the compiler changes in a way that lets it keep up with recent compiler versions, plus eventually replace its odd custom Ninja-based build system with OCaml ecosystem stuff (dune for build, esy for packages).
I saw your comment about problems with Clojure modes in editors. Have you tried Light Table yet? I used it for a while; it's made with Clojure(script) so it has pretty good interaction with Clojure. The impression I got when using it was "this is a modern emacs", and I mean that in a good way. I eventually quit using it for cider+emacs, but only because they quit doing 32-bit builds at a time when my Debian install was still 32-bit.
Configuration isn't the most user friendly — you edit EDN structures directly — but that shouldn't be a deal-breaker since 1. you know Clojure and 2. VSCode's "edit JSON structures" configuration is no better.
Are you looking for something similar to C++, in spirit at least? If not, then see the other replies. If you are, then you might like Scala.
C++ is a multi-paradigm language with limited support for functional programming. Scala is a multi-paradigm language with first-class support for functional programming. Both are complex (some say too complex), powerful, flexible, and expressive, and both provide access to a whole platform of libraries: native code in the case of C++ and the JVM in the case of Scala.
Scala's biggest drawbacks are its complexity (which is reportedly being worked on) and slow compilation times (which can somewhat be worked around). It's also worth mentioning that cut-down versions of Scala's OO/FP combo are available in other JVM languages, the most popular of which is Kotlin, which has native interop (via Kotlin Native), and decent FP support without most of Scala's complexity or caveats.
You can wrap and reuse native code (written in C++ or anything else) via Scala Native.
Scala is used in finance, though not as much as C++.
I know you aren't asking for it but there's a book on functional programming in JS hidden behind the mysterious title Grokking Simplicity
Or, why you should learn Abstract Algebra (eg.) to get deeper in FP :).
An amazing talk that I was very fortunate to watch live.
Its too verbose but it also won't drown you in theory like a lot of other suggestions you'll probably get. It also uses javascript for the examples but at the same time doesn't really promote javascript as a functional language.
> the type system isn't nearly as powerful as the other languages
"Powerful" is subjective, but I disagree. In some ways TypeScript's type system is more powerful than a lot of languages I've used (two examples: it has type operators which make it trivial to derive types from other types and from values, and contextual typing is ridiculously useful).
However it is also different from many other type systems, leaning structural instead of nominal. It's also intentionally unsound, favoring ergonomics over correctness in some cases. And the fact that there are no "exact" types to constrain structural subtyping (coupled with the fact that the runtime lets you do things like dynamically iterate over object properties) can lead to surprises. TypeScript is held back by JavaScript in other ways too, e.g. there is no native pattern matching syntax.
I'd call it "lax", but "powerful" at the same time.
I use HKTs in TypeScript at my current job (with fp-ts), but I miss some things from Scala. Mostly implicit resolution/first-class type classes. It gets tedious to manually thread type class instances through function calls, and because of that I write less generic code than I would otherwise.
As for monads and recursion I only studied it in a strict evaluated setting so far. In purescript there is the `MonadRec` type class. Scala uses a `Trampoline` monad, which was inspiration for this JS implementation.
I can mimic thunks and WHNF in JS with the native `Proxy` type. Probably will do some research soon how lazy evaluation affects monadic recursion. I hoped that guarded recursion would kick in. But guarded recursion seems to require that the outermost level of an expression is a value constructor. Can't be of much help at the moment, sorry.
Just wondering, why you do assume that strict positivity is inherently needed for a type theory to be consistent? That is not true at all. For example, elementary affine logic is compatible with strict positivity. Formality-Core doesn't do any termination checking though, it should be seen as a pre-proof language that supposed to be supplemented with external termination checkers. There are models where self holds, check Aaron's paper. Here is my take on consistency.
> I do sometimes define functions like a => b => c, but usually only if I'm going to be frequently dealing with data of the type b => c. Maybe I have a map of as to b => c functions, so it really does need to be a function returning a function.
Sure, that's fair enough, but I'm not sure that's really what we're talking about. In that case, you're really just writing a function a => b where b happens to be a function.
I'm more concerned with this idea of defaulting to writing curried functions when you aren't already sure that you want a function b => c as an actual value to be passed around.
> I'm not sure what you mean when you say currying adds syntax noise. I can agree that isLessThan(a)(b) is noisier than isLessThan(a, b), but that's why the curry function I'm using allows both usages.
I mean at the definition site, not the call site. It's not a huge deal, granted, but it's still extra to write const isLessThan = (a) => (b) => a < b
, and is only going to be noisier when the function isn't trivial.
> But I do think that nums.filter(isLessThan(4)) reads almost like English and is less noisy and more intentional than nums.filter(n => n < 4).
Actually, I've been bitten by JavaScript's higher order functions enough that I won't actually pass functions directly to them anymore, anyway (Gotcha #1 here: https://dev.to/danhomola/point-free-gotchas-in-javascript--3pfi).
> No, my point is WASM's situation is so unattractive, we can't even start to speculate what's exciting about it.
These people are pretty excited about it. But I'm sure you'll come up with a reason why that doesn't count either.
I'd add Elm to between these two lists as well. It doesn't compromise: it is "pure" (no side-effects) and strongly-typed. But it keeps itself simple by avoiding the complexities of GHC's million extensions.
Racket is particularly well-equipped for programming instruction, including integration with the DrRacket IDE. See more input on why Scheme is good for learning programming. Also there is very little syntax to learn in a Lisp/Scheme-like language. Honestly I wouldn't bother trying to teach someone introductory programming in any other FP language, especially not a more pure language.
I think that Clojure dying talk is rather overblown to be honest. I gave a more detailed answer regarding that here.
Basically, I'm seeing is that Clojure has transitioned from being a hip new language to one that people are primarily using for work now. Cognitect also started a recent success stories section on their site, where you can see how companies are using it.
I'm a big fan of Code Wars for toy problems. A lot of variety there, so I am sure you can find functional focused stuff. Also, keep in mind most problems can be solved in a functional way. So in theory, any toy problem should do. Also also, a good gateway drug for FP in JS are array methods like map, filter, and reduce. So keep your eye out for array problems.
As you can see here in the docs, function types do use fat arrows.
You'd be right if this were a function declaration of the form
function push<A>(item: A, arr: A[]): A[] { arr.push(item); return arr; }
But as an anonymous function assigned to a variable, the syntax I gave is right.
The danger with hybrid languages like Scala is that you may fall back on doing things the familiar way, if that way is open to you.
I strongly dislike Scala, but I think it may suit you. Check out Functional Programming in Scala too.
There's a really good book that pretty much takes you closer and closer to designing a recursive functional construct in racket called
https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0262560992/ref=sr_1_1?dchild=1&keywords=schemer&qid=1609605810&sr=8-1