Also, I really like this post: https://fsharpforfunandprofit.com/posts/low-risk-ways-to-use...
> We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).
let transition (state: State) (action: Action) : State option =
match (state, action) with
| (StateA, ActionA) -> Some StateB
| (StateA, ActionB) -> Some StateC
| (StateB, ActionA) -> Some StateB
| _ -> None
If you get the quoted representation of the transition function, it can be visualized as a tree data structure (like code-as-data in LISP). You can analyze that tree to understand that if current state is StateB, only ActionA can be applied on it.Couple this with another realization: "Any sufficiently complicated model class contains an ad hoc, informally specified, bug-ridden, slow implementation of half of a state machine." (not sure where I read this quote).
This means all the entity framework/ORM crap work that we do can actually be neatly represented as transforms on a F# state machine, which suddenly makes the application more powerful if you give it this structure.
We use this technique to auto-generate admin panels.
Can’t tell you where you read it, of course, but believe it originates from Braithwaite/raganwald:
You can do similar things with other Ocaml or Lispy Langs, depending on how you want to do it. All you need is a function that returns possibleTypeTransitions for givenType(type, enclosedLexeme, type.validTransitions). A gradually typed lang sitting in top of a prototype-based blob also makes this easy to do (see typescript) in-codo.
See also MacKay (RIP)'s classic book: http://www.inference.org.uk/itprnn/book.pdf
I'm really having fun experimenting with F# for my API server, but I hesitate to use it on the front end.
Trying to figure out how to map to an overloaded C# callback (maybe hidden in an *.extension doc!) has wasted hours of my time.
F# (the ml family in general) is my favorite language right now but, man, the .net APIs are rough.
Lacking the same UX I’m used to in Node, Ruby, and Elixir.
Example here is the String doc[1]. Way down you see all the methods. Some of the methods have overloads (multiple variants). Pretty straightforward here. (E.g. `"mystring".Contains("ring")`)
Where it gets more verbose and finicky is when the API takes a C# callback. Even more complex is if it’s asynchronous so it takes a C# callback as a Task.
An example being the `.Use` method for defining server middleware.[2]
To see how it’s done, here’s a gist I found.[3] Notice how the function for requestHandler is verbosely annotated with Func<> and RequestDelegate, etc.
Luckily this isn’t the norm, most APIs are less complicated. Even so, you write a wrapper (abstraction) around that complexity and only look at your wrapper. Which is why someone in this thread said to leave them in a dark corner.
[1]: https://docs.microsoft.com/en-us/dotnet/api/system.string?vi...
[2]: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnet...
[3]: https://gist.github.com/kspeakman/7870a75283f6942dd96ff34a03...
https://www.nuget.org/packages/TaskBuilder.fs/ https://github.com/rspeele/TaskBuilder.fs
All our new code is in F#, we started off from a C# codebase, so that made the transition somewhat manageable, as new F# code can be directly called from C#, and vice versa (still took over 2 years). All new frontend apps are also being written in F# (using Fable), as of 6 months back, migrating away from TypeScript, this forces everyone into a "design your model first, and well" paradigm. We've written quite a bit of code to blur the lines between traditional backend and frontend development roles, so what we have now are:
- product engineers (who write application logic on both frontend and backend to serve business needs)
- platform & framework engineers (who write the underlying persistence/serialization/versioning/frontend-backend-sync websocket/load balancing/IDE extensions/deployment etc)
- component designers who focus on visuals
Platform/framework engineers try to encapsulate as much magic as possible into computation expressions (F#'s monads), so product engineers can focus simply on writing out business intent, with readability given very high priority. We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).
Our code written in F# has an order of magnitude fewer bugs when it makes it to production, given the amount of thought we pour in modelling the problem domain accurately, and thanks to functional programming itself. They're also more amenable to business requirements changing, simply because they've been modelled well to start with. Nothing that can't be achieved in other languages, but with F#, this happens more naturally.
Almost everyone in our team has learnt F# on the job, and overall, everyone's experience has been extremely positive. There's a bit of difficulty in the first 2-3 months, as junior devs get introduced to functional thinking, but if you've generally being doing functional programming, this is just about learning new syntax, tooling and F#'s choice of operator naming (map/bind/pick/collect/choose/..). Typically, based on prior experience, we ask newcomers to spend two weeks to a month, solving the first 100 problems on Project Euler in F#, without using the mutable keyword, and we assign a mentor to point out best practices and review their code.
The hiring pool for F# devs is much smaller than the regular applicant pool, but if a candidate shows genuine interest in F#, they are usually 10x more likely get through our interview process. If they've discovered F#, it means they find something lacking with mainstream languages, so they're likely to have many years of experience under their belt, and they've found a way to grow. That said, we don't restrict our hiring to simply F# devs.
For more info about us, see chaldal.tech (YC/S15).