[HN Gopher] What I wish I knew when learning F#
       ___________________________________________________________________
        
       What I wish I knew when learning F#
        
       Author : DeathArrow
       Score  : 206 points
       Date   : 2021-10-14 12:07 UTC (10 hours ago)
        
 (HTM) web link (danielbachler.de)
 (TXT) w3m dump (danielbachler.de)
        
       | Multicomp wrote:
       | I am building a tabletop game trainer for Star Wars FFG as the
       | RPG Sessions app is incomplete and trying to do all of the things
       | manually or remember every rule + every modifier to the rule +
       | what all of my NPCs stats are is impossible, and thus when one
       | looks things up, it slows down gameplay a lot, especially during
       | battles. Since the whole point of the system is to make battles
       | feel fast and cinematic, and we want to strictly adhere to the
       | rules as written so we are not constantly re-adjudicating (read:
       | bickering over) house rules, we need something more.
       | 
       | Enter F#. I've been working on (yet not releasing a usable
       | version yet bc I'm bad) this program entirely in F#, using
       | Giraffe as the web layer, following the general architecture
       | defined in Domain Modelling Made Functional, and using Dapper to
       | write to a Sqlite database.
       | 
       | F# is amazing. I'm able to fully understand the codebase and
       | follow exactly what happens from HTML Form request, through input
       | validation, through the business logic, down to the database and
       | back to the domain, then rendering out to a JS-free webpage via
       | Giraffe.
       | 
       | It gets tedious doing the marshalling/unmarshalling from HTML
       | form to input DTO to domain type to output DTO to database
       | records to input DTO etc. and I need to learn both how to create
       | DSLs (so users can type in rules from the book and the system
       | will extract the keywords and compose them into the closest
       | equivalent set of conditions and effects the system supports) and
       | lock down my bounded contexts so I'm developing them in order of
       | least to most entity dependencies rather than in order of where I
       | feel I need them most, but I can't see a way where I would be
       | able to build this in plain old C# without all of my above
       | challenges + lots of boilerplate code to ensure my expected
       | invariants are met and someone (me) hasn't changed an invariant
       | out from under me somewhere else without realizing it.
        
         | 2mol wrote:
         | Yeah, those boundaries between beautiful domain type <-> DTO
         | <-> database is also something my team and I struggle with. In
         | the end we're happy with just writing it out, but there is this
         | nagging feeling that it could be more ergonomic.
         | 
         | I'd be interested to hear about other approaches. You could in
         | theory just dump (automatically generated) JSON to the database
         | and evolve your types with tagged versions, but then you have
         | to write some boilerplatey converters between TypeV1, TypeV2,
         | TypeV3, ...
         | 
         | I guess that's the price for staying away from full-blown ORMs?
         | 
         | It reminds me a bit of how in Elm you just suck it up and write
         | the JSON en-/decoders by hand. Annoying at first, but then you
         | get super obvious and maintainable code out of it, which is
         | quite a joy.
        
           | iudqnolq wrote:
           | I kind of like the Elixir Ecto approach where your "DTO"s are
           | mostly plain old data with a single hidden attribute
           | identifying the database table and some other db metadata.
           | They're not live/active, you have to manually pass them to
           | functions to update, but you avoid having two nearly
           | identical types.
        
           | de_keyboard wrote:
           | > It reminds me a bit of how in Elm you just suck it up and
           | write the JSON en-/decoders by hand. Annoying at first, but
           | then you get super obvious and maintainable code out of it,
           | which is quite a joy.
           | 
           | The F# take on Elm coders (Thoth.Json) can use reflection to
           | generate them automatically. This is really useful at the
           | prototyping stage.
        
             | 2mol wrote:
             | Yup, I love Thoth. At work we just use System.Text.Json +
             | FSharp.SystemTextJson though, that also generates
             | (de)serializers, and it has a bunch of options to fine-tune
             | naming conventions, sum type encoding, etc. Super useful
             | and easy to hammer out the correct type for very big and
             | nested JSONs.
        
       | chalst wrote:
       | The main thing I found strange about F# was that, having prior
       | familiarity with Ocaml and SML/NJ, was that what F# calls modules
       | are completely unlike the module system of any other ML-inspired
       | language, being instead an adaption of C# classes to serve F#'s
       | namespacing needs. Since the module system is of similar
       | importance to code reuse to Haskell's typeclasses,the relative
       | deficiencies of F#'s module system hurt.
        
       | infogulch wrote:
       | There was a recent thread about Algebraic Effects in OCaml [0].
       | Does F# have something similar?
       | 
       | [0]: https://news.ycombinator.com/item?id=28838099
        
         | Smaug123 wrote:
         | No. It has lightweight syntax ("computation expressions") you
         | can use to sugar monads, but no effects system.
        
         | xvilka wrote:
         | It lacks many things that OCaml has. On the other hands, units
         | support is awesome, I wish there would have been more attention
         | to that, and more popular in other languages as well.
        
       | muglug wrote:
       | > It has a scripting mode where compilation is done on the fly.
       | This makes it look and feel very similar to python but you still
       | get type checking and much better performance.
       | 
       | This is a really wonderful quality in a compiled language. I wish
       | there were more languages with this attribute (but it's a lot to
       | ask for).
        
         | BBC-vs-neolibs wrote:
         | Crystal, the compiled-but-super-fast statically typed _Ruby_
         | dialect.
        
       | eatonphil wrote:
       | I've had good experiences running F# on Linux. I used it to build
       | an API generator from database schemas [0]. Similar to Go you can
       | get a single static binary you can copy anywhere.
       | 
       | It's very convenient and you've got a massive number of .NET APIs
       | to fall back on.
       | 
       | The language is a little complex though. That you cannot call
       | interface methods on an object implementing the interface without
       | explicitly casting to the interface [1] is pretty weird. And
       | getters/setters are a little complex.
       | 
       | If you want an easy introduction to the ML family for
       | educational/historic sake I'd always recommend Standard ML. But
       | if you want a highly pragmatic, mature, strictly typed, compiled,
       | cross-platform language F# is pretty compelling.
       | 
       | [0] https://github.com/eatonphil/dbcore
       | 
       | [1] https://docs.microsoft.com/en-us/dotnet/fsharp/language-
       | refe...
        
         | beecafe wrote:
         | at least they picked cute bird face emoji for it :>
        
         | nextos wrote:
         | It's also important to add F# is an inspiration for an amazing
         | MS Research effort, F* [1].
         | 
         | Furthermore, it is also worth checking Dafny [2] (Spec#'s
         | successor). The relationship between Dafny and C# is equivalent
         | to the relationship between F* and F#. Both languages try to
         | refine their predecessors semantics and augment them with
         | practical constructs to prove program correctness.
         | 
         | Some of the largest software artifacts ever verified have been
         | implemented in Dafny [3], and F* is also looking quite
         | promising.
         | 
         | [1] https://www.fstar-lang.org
         | 
         | [2] https://dafny-lang.github.io/dafny/
         | 
         | [3]
         | https://www.cs.columbia.edu/~junfeng/17sp-e6121/papers/ironf...
        
         | phillipcarter wrote:
         | The language, in general, wants you to be explicit about what
         | you're working with. So implicit access to interface members
         | isn't a thing, you need to say that "x is this interface type"
         | or cast.
         | 
         | In F# 6 things are changing a bit, and may possibly change in
         | the future. There are various classes of cases where the type
         | information is known, but the compiler still required you to
         | explicitly cast things to be happy. That's no longer case. This
         | link[0] has 3 examples that don't compile with F# 5 but will
         | compile with F# 6.
         | 
         | [0]
         | https://sharplab.io/#v2:DYLgZgzgNALiBOBXAdgHwPToAQFMAeAhgLYA...
        
           | Dayshine wrote:
           | Implicit upcast? That's amazing, I feel like that's going to
           | help a lot with many branched functions.
        
             | phillipcarter wrote:
             | Yeah, it's a good feature. It's been done carefully --
             | there's room to do more of this kind of upcast conversion
             | in the future -- but there's also a danger of creating code
             | that behaves weirdly, too. See here for some of the dangers
             | in Scala 2: https://latkin.org/blog/2017/05/02/when-the-
             | scala-compiler-d...
        
           | TravHatesMe wrote:
           | > implicit access to interface members isn't a thing, you
           | need to say that "x is this interface type" or cast.
           | 
           | If the compiler already knows that it implements interface X
           | Y and Z, it seems unnecessary to require it (unless those
           | interfaces have conflicting names, in which case you would
           | have to be explicit due to ambiguity).
           | 
           | I feel like many languages are walking away from being so
           | explicit, in particular I've noticed C# becoming more
           | implicit over the years.
        
       | bob1029 wrote:
       | If you want to dabble in functional, C# is actually a compelling
       | option now. Switch expressions and LINQ can take you a long way.
       | 
       | I strongly believe that functional programming is not a good fit
       | for 100% of software architecture. The best is some sort of
       | hybrid. Generally, the closer you get to the business logic, the
       | more functional you would want to be. The serializers, http
       | servers, etc. are probably not worth the squeeze to force into a
       | functional domain.
        
         | enricosada wrote:
         | C# switch are just syntactic sugar. nice for sure.
         | 
         | But if you compare F# with C#, is not just LINQ .Select vs
         | List.map
         | 
         | And i am not speaking about function, who is just a part of why
         | i like F#, not the best one
         | 
         | Is the different defaults who matter, who guide you to an
         | easier code who highlight the domain
         | 
         | - structural comparison vs reference comparison - expression vs
         | statement based - immutability
         | 
         | C# will catchup with some features for sure.
         | 
         | Lot of new C# feature remove boilerplate (file scoped
         | namespace, etc) and is a good trend
         | 
         | But the core defaults will be the same.
         | 
         | That will not push to a single direction (if fact you have LOTS
         | of way to write the thing in C#) while F# try to push to the
         | same way
         | 
         | To do so, C# continue to add thing to the LANGUAGE. Now is a
         | lot more complicated than .NET 2.0
         | 
         | While F# try to do the same, but the language doesnt change.
         | 
         | An example: the async/task.
         | 
         | C# added the async as keyword, plus all needed to make it work,
         | and the compiler generate special code.
         | 
         | F# has built that from the general computation expression
         | feature and (recently) the state machine support.
        
         | wyager wrote:
         | > The serializers, http servers, etc. are probably not worth
         | the squeeze to force into a functional domain.
         | 
         | These are two examples I would probably come up with if you
         | asked me "where does FP thoroughly beat imperative?"
         | 
         | (De)Serializers - parser combinator libraries like attoparsec
         | absolutely BTFO imperative parser libraries in most dimensions.
         | Bidirectional codec libraries like haskell's Binary, Serial,
         | Aeson[1] are top-tier. Functional formatters like Blaze are
         | top-tier as well.
         | 
         | Haskell's HTTP ecosystem is massively better than anything else
         | I've used, and I went on a binge of trying a ton of HTTP
         | servers like 6 years ago (in python, ruby, C++, Go, and finally
         | Haskell).
         | 
         | [1] https://github.com/lovasoa/bad_json_parsers
        
         | JoelMcCracken wrote:
         | I initially believed this, but I have come to realize that pure
         | functional programming is transformative for both business
         | logic and infrastructure. Its a lot easier to get started in
         | the business logic side; dealing with effects in the context of
         | pure functions is a lot to figure out, I don't even know if you
         | really _can_ do it in not-haskell. But, via Haskell I have been
         | able to achieve far greater levels of producitivty in these
         | tasks than ever before.
         | 
         | The main downside is that its a lot to learn, and it takes a
         | good while before you get productive. But I am absolutely more
         | productive now in Haskell than just about anything else, save
         | perhaps ad-hoc text munging task; the shell DSL is just so
         | handy for random one off stuff.
        
         | Koshkin wrote:
         | Sure - C# is the best functional language, while Haskell has
         | already been the best imperative language for a while now [0].
         | 
         | [0] https://stackoverflow.com/questions/6622524/why-is-
         | haskell-s...
        
         | GuuD wrote:
         | I would have to respectfully disagree with you on the
         | serializers part here. For me, after decades of fighting with
         | "magic" stuff, simplicity is the key feature. So, everything
         | that is a simple map function in disguise I tend to stick with
         | functional languages and approaches.
        
         | kevinmgranger wrote:
         | I think it's really hard to properly define "functional
         | programming" concretely, but I'll partially agree. If all a
         | language takes from FP is:
         | 
         | - make composition ergonomic, idiomatic, and easy (including
         | the usual iterator map/reduce, etc.)
         | 
         | - let the type system protect you (including nullability)
         | 
         | Then you've already got the most important strengths, in my
         | opinion.
        
           | grumpyprole wrote:
           | Functional programming is not just programming with closures.
           | It's about "referential transparency". Referential
           | transparency permits higher-level mathematical reasoning,
           | which leads to safer/better program composition,
           | optimisations, caching/reuse and parallelisation/concurrency.
           | If you are willing to concede mutable-state and other
           | uncontrolled effects, there is much to be gained.
        
             | dboreham wrote:
             | Citation needed.
             | 
             | <ducks>
        
         | mumblemumble wrote:
         | I agree that 100% functional is not necessarily the way to go.
         | That said, I am a _big_ fan of F# 's "functional first" ethos,
         | which drives you toward that sweet spot of a functional core
         | inside of an imperative shell.
         | 
         | With C#, when I'm trying to use functional design, I often feel
         | like I'm swimming against the current. The language has
         | functional features, and it will certainly let you use them,
         | but, LINQ aside, the path of least resistance is mostly
         | imperative and object-oriented.
         | 
         | In F#, it's the other way around. It has a full suite of
         | object-oriented features - still, after all these years, quite
         | a bit more complete than C#'s suite of functional features -
         | but the path of least resistance is mostly functional.
         | 
         | I don't want to say that's a universal best way to have things.
         | But it suits my taste, because it makes the easiest way to do
         | things correspond very closely with the way I like to see
         | things done: distinct and well-distinguished layers of
         | functional and object-oriented code, sorted according to where
         | each is of the most utility. C#, by contrast, tends to guide
         | you toward a foamy lather of functional and object-oriented
         | code with no identifiable organizing principle.
        
           | barrenko wrote:
           | This is the same issue I have with Javascript. If you _don
           | 't_ have to use something, you just won't, or maybe I'm just
           | lazy.
        
         | ulucs wrote:
         | I think serializers would be better off as railways, allowing
         | you to combine small serializers while also collecting the
         | errors so you end up with a conclusive outcome. Haskell's
         | parser combinators are quite fun for example.
         | 
         | Also I've only used node/elixir serverside, but aren't http
         | servers just a huge pipeline? It fits quite well into
         | functional programming.
        
           | bob1029 wrote:
           | > aren't http servers just a huge pipeline
           | 
           | Absolutely. At a certain level of abstraction they can be
           | viewed in this way.
           | 
           | How do HTTP servers actually get packets to and from the
           | machine? At some point you have to interact with the
           | operating system. This is not a realm where functional
           | programming is very feasible today.
        
         | de_keyboard wrote:
         | > The serializers, http servers, etc. are probably not worth
         | the squeeze to force into a functional domain.
         | 
         | I used to think the same, but having now tried FP-style
         | libraries for serializers (Thoth.Json) and HTTP servers
         | (Suave), I think they are far superior to imperative or OOP
         | alternatives. The ability to design these things in a
         | declarative style makes the code much more robust _and_ easier
         | to read.
        
           | JaggerJo wrote:
           | +1
        
           | dustingetz wrote:
           | FP is better on a 30 year timeframe but on a next-quarter
           | timeframe probably still has not "crossed the chasm" - you
           | need not just something accessible like ZIO but you need to
           | figure out what it's killer app is, which the FP community
           | currently doesn't have a clue. "HTTP server but more
           | declarative and made with monads" is not something people
           | cannot live without
        
             | de_keyboard wrote:
             | I think this depends on the relative weights you assign to
             | learning a new language and program correctness.
        
         | ghostwriter wrote:
         | > I strongly believe that functional programming is not a good
         | fit for 100% of software architecture. The best is some sort of
         | hybrid.
         | 
         | Haskell would be a better language in every domain where C# is
         | applicable. That is from a language perspective, abundance of
         | libraries is a different question, as it's a matter of the
         | community size and attention.
        
           | dboreham wrote:
           | I think enforced purity is problematic (although obviously
           | useful for some purposes such as program correctness proofs).
           | I still want to be able to write:
           | 
           | doThing1();
           | 
           | // thing1 has finished
           | 
           | doThing2();
           | 
           | Where the functions block. Async and Monads and Futures and
           | all are useful for some things, but mostly I just want to do
           | stuff sequentially, blocking, and not confuse myself.
           | 
           | Scala allows this, although the widespread Future-ification
           | of libraries makes it hard to actually practice.
        
             | ghostwriter wrote:
             | Haskell allows this too, users can just code everything
             | within IO until they feel comfortable with adding extra
             | purity through refactoring:                   main :: IO ()
             | main = do             myBusinessLogic
             | myBusinessLogic :: IO ()         myBusinessLogic = do
             | doThing1             doThing2              doThing1 :: IO
             | ()         doThing1 = do             putStr "Hello "
             | doThing2 :: IO ()         doThing2 = do
             | putStrLn "World"              ---         ghc -o main
             | main.hs         [1 of 1] Compiling Main             (
             | main.hs, main.o )         Linking main ...          ./main
             | Hello World
        
               | dboreham wrote:
               | True. Perhaps my issue is that I know how that's
               | implemented and my brain can't see it the same as
               | sequential statement execution ;)
        
               | JoelMcCracken wrote:
               | This is a function of familiarity though. Get familiar
               | with it and you'll understand it just fine.
               | 
               | If you want to talk more about it, feel free to email me.
        
               | tome wrote:
               | I think dboreham's objection was exactly the opposite!
        
               | JoelMcCracken wrote:
               | Idk i mean simply knowing what the code for >> looks like
               | doesn't mean you're used to thinking in that way.
               | 
               | There was a time years ago when someone was showing me
               | the types of (>>) and (>>=) in Haskell and my question
               | was "ok, but what does that have to do with IO?!?"
        
         | grumpyprole wrote:
         | The creator of LINQ, Erik Meijer, wrote a fun article "The
         | curse of the excluded middle: Mostly functional programming
         | does not work". Yes it's tongue-in-cheek and highly
         | provocative, but many of his points are true. There is a lot
         | more yet to be learned from functional programming than LINQ
         | and switch expressions.
         | 
         | https://queue.acm.org/detail.cfm?ref=rss&id=2611829
        
           | aranchelk wrote:
           | Is it meant to be tongue and cheek? I personally didn't get
           | that impression. I assumed he was using the non-religious
           | meaning of "fundamentalist": strict and literal adherence to
           | a set of principles.
        
             | grumpyprole wrote:
             | I mean it has a deliberately highly-provocative style. But
             | the points he raises are all completely valid.
        
           | feoren wrote:
           | This is _such_ a weird article. All of his examples are
           | insane strawman non-idomatic C# code, and then he complains
           | when they don 't do whatever he decides "an average
           | programmer" would expect them to do. Huh? They were all
           | either doing exactly what I expected them to do (silly
           | things), or were so strange and alien that even Visual Studio
           | has no idea what to do with them! I've never seen anything
           | like that Cell<T> example and it doesn't come close to
           | compiling. What a weird, weird thing to do: write code that
           | literally _does not compile_ and then complain about it!?
        
       | codingclaws wrote:
       | This is off topic. I can't resist - that's the thickest sticky
       | header I've seen from a developer.
        
         | gorgoiler wrote:
         | Yes, hah, I too was impressed with the chutzpah of having...
         | 
         | "DANIEL"
         | 
         | ...on a substantial amount of my screen throughout the whole
         | read.
        
       | JayGuerette wrote:
       | His claimed inspiration, Hillel Wayne's post "Why Python is my
       | Favorite Language", is a piece of fluff that basically says "I
       | only like the things I already know". I was so _uninspired_ , I
       | couldn't read further.
        
         | loic-sharma wrote:
         | You fault an article for being superficial while yourself only
         | giving a superficial read? I hope you see the irony and
         | reconsider.
        
       | ur-whale wrote:
       | Is there a FOSS compiler for F#?
        
         | gameswithgo wrote:
         | the Microsoft .net core compiler is FOSS, but if that doesn't
         | count there is also mono.
        
           | ur-whale wrote:
           | > the Microsoft .net core compiler is FOSS
           | 
           | Oh, I didn't know that.
           | 
           | Very cool.
           | 
           | Can I apt-get the toolchain?
           | 
           | [EDIT]: and for those interested, here's the github repo:
           | 
           | https://github.com/dotnet/fsharp/
        
             | DeathArrow wrote:
             | Yes, you can.
        
               | ur-whale wrote:
               | > Yes, you can.
               | 
               | I can indeed.                   apt-get install fsharp
               | 
               | (although it pulls in 300MB of dependencies :( )
               | 
               | This is great.
               | 
               | How times have changed!
        
               | chusk3 wrote:
               | I wouldn't do this, as this is the mono bundle of fsharp.
               | The blessed/supported way to go now is to install the
               | dotnet-sdk packages[1] and then use `dotnet fsi` for
               | interactive work, and `dotnet build/run/etc` for project-
               | based work in F#.
               | 
               | 1: https://docs.microsoft.com/en-
               | us/dotnet/core/install/linux-d...
        
               | ur-whale wrote:
               | I'll give it a shot, but TBH, I like the no-brainer apt-
               | get way.
               | 
               | Goal is not to spend a couple of hours fighting to
               | install the stack, but to use the time learning about the
               | language.
               | 
               | apt-get gives me that.
               | 
               | MSFT-specific stack install tool don't really sound like
               | a no-brainer, but I'll look anyways.
        
               | aloisdg wrote:
               | As a fellow linux user, my package manager does the job
               | for both the runtime and the sdk. It should work for
               | yours too.
        
             | enricosada wrote:
             | See https://dotnet.microsoft.com/download
             | 
             | Download the Sdk, who bundle both the runtime and the C#/F#
             | compilers (everything you need to build a program) and the
             | `dotnet fsi` REPL
             | 
             | All of that is open source, developed in different repos
             | and bundled there in a nice installer.
             | 
             | Support all platform and can cross compile for other OS
             | 
             | Please do not use Mono, because contains an old version of
             | F# and lots of quirks to use.
             | 
             | The current way is .NET (was called .NET Core, renamed
             | recently) because is cross platform by design, and
             | eventually Mono will be merged 100% there.
             | 
             | Plus is tons more performant and better tooling
        
             | ddek wrote:
             | You can, but I wouldn't. The dotnet CLI contains its own
             | version manager, so you need to have more precise control
             | over the versions of the runtime & sdk you have installed.
             | You can have multiple versions installed simultaneously,
             | dotnet then chooses the runtime based on the project. IME
             | linux package managers mess this up bad.
             | 
             | Fortunately MS provides a better alternative: the dotnet
             | install scripts. [0] Make sure you add the install
             | directory to $PATH.
             | 
             | [0] - https://docs.microsoft.com/en-
             | us/dotnet/core/tools/dotnet-in...
        
               | ur-whale wrote:
               | > so you need to have more precise control over the
               | versions of the runtime & sdk you have installed
               | 
               | Oh, this doesn't sound good at all.
               | 
               | One thing I positively _hate_ about Java is always having
               | to worry about which version of this and that (sdk, vm,
               | headless, etc...) you run on top of. The claim of write
               | once run anywhere has not really happened in my book.
               | 
               | Even C++ is better in that regard these days.
               | 
               | I am certainly hoping the .NET / F# environment didn't
               | inherit that attribute from the Java ecosystem, that'd be
               | a major downer.
               | 
               | My goal is only to learn F# / experiment with it, and I'm
               | certainly hoping _never_ to have to spend a second
               | thinking about  "versions of the runtime & sdk".
        
               | piaste wrote:
               | If you just want to learn, install the latest version of
               | the SDK (.NET 6, currently in RC) and it will be able to
               | build code or reference libraries from every older
               | framework version.
               | 
               | Runtime versions are something you worry about when you
               | are actually deploying / distributing applications.
        
             | orra wrote:
             | > Oh, I didn't know that.
             | 
             | In fact, F# has been open source longer than Roslyn (the
             | C#/VB.NET compilers) and .NET Core!
             | 
             | There used to be a funny split in the repos: Microsoft had
             | their own visualfsharp repo, and there was a blessed fork
             | which was more community and Linux friendly.
        
           | BBC-vs-neolibs wrote:
           | ... to be clear, Mono does not provide F#. Microsoft releases
           | F# for Mono.
        
             | UK-Al05 wrote:
             | F# and .net core are completely open source. You don't need
             | mono.
        
         | Smaug123 wrote:
         | You can simply contribute to https://github.com/dotnet/fsharp/,
         | the maintainers are very friendly to new contributors in my
         | experience (though the codebase is _old_ and often quite hard
         | to understand).
        
           | phillipcarter wrote:
           | > though the codebase is old and often quite hard to
           | understand
           | 
           | Even some new stuff is like that - and partially my fault,
           | depending on the area :)
           | 
           | That said, some stuff that was REALLY tough to understand was
           | ripped out recently, the "reactor queue" and incremental
           | build system. They were central to how editor tooling works
           | and utterly incomprehensible since they were working around
           | the lack of a free-threaded compiler service. Now the entire
           | compiler is free-threaded, so all the complex machinery to
           | coordinate work is mostly deleted and/or reduced to like 50
           | lines of straightforward code.
        
             | enricosada wrote:
             | As a note, the codebase is also huge because contains lot
             | of code:
             | 
             | - FSharp.Core library, who contains most of the types and
             | functions you want to use
             | 
             | - the fsc F# compiler
             | 
             | - the FSharp.Compiler.Service, who is the compiler as a
             | library used by all editors/ide, written to be performant
             | and support the logic of IDE functionalities (find
             | references, etc)
             | 
             | - The Microsoft Visual F# code, who is the F# extension for
             | Visual Studio
             | 
             | So is complicated repo, but for a reason. But nice to work
             | with given the features there
        
       | steve76 wrote:
       | > Scott Wlaschin's fsharp for fun and profit is one of the best
       | functional programming resources I know across all functional
       | programming languages.
       | 
       | Hey! Someone else saw this. Very underrated resource. Also
       | Professor Frisby's Mostly Adequate Guide to Functional
       | Programming needs more attention too.
       | 
       | Things I would add:
       | 
       | 1. Start off with what types you need, not functions. Creating
       | your types like the tools you need to do the job. Then build
       | combinators. Convert one complex type to a primitive. Then a
       | primitive to your type.
       | 
       | 2. Once you have your types, it's not that difficult to make them
       | functional. You just make methods for "of", or "chain", or "map",
       | or "ap". Now you have monadic and applicative interface.
       | 
       | 3. The functional part is just like when a shell drops to a
       | program's prompt, like >ftp and >mysql. You setup a series of
       | commands like that, with Either or Task or Fold. Provide input,
       | prepare a list of commands, and then run them when everything is
       | valid and ready.
       | 
       | 4. Bundle size is a problem for web. Until tech improves and
       | bandwidth prices lower, 100 KB on a high volume website is a
       | problem. Nothing wrong with taking a proven solution, like
       | wordpress, and caching it.
       | 
       | 5. Property based testing is for under the hood, your types and
       | combinators. It's not something you do with Cypress or units. All
       | that input is type unknown, and needs validation before going to
       | what's coverage under property based testing.
       | 
       | 6. One fault that always occurs is trying to use Runtime encoding
       | to build some extensible modular program. Don't do that. Types
       | are for build. Validation is for runtime. If it doesn't validate,
       | show a user a message. Don't try to build some hot swappable
       | modular program, where types are read from input. If they want to
       | program the computer, they can install the IDE.
        
       | rcarmo wrote:
       | Pretty much on point. I've been building a .NET, bootstrapped
       | webapp (i.e., no Razor, no "cargo culting" so I can actually
       | understand things from the ground up) piecemeal, every other
       | weekend, in both C# and F#, and, like Java before it,
       | _understanding the ecosystem and libraries_ is critical.
       | 
       | I can read OCaml and dabbled in it, but that doesn't help me
       | write substantially better .NET because I will be iterating over
       | lists or graphs in a different way, handling IO (and sockets)
       | differently, etc.
       | 
       | But I can see how someone conversant with C# and the .NET
       | ecosystem would really like F# since the barrier to entry is
       | substantially lowered, and the code is just so much nicer and
       | tidier.
       | 
       | Shame there isn't a proper AOT-compiled LISP for .NET (no,
       | Clojure doesn't count, I never managed to get the .NET version to
       | work for me).
        
       | mickjagger wrote:
       | What does F# do that other languages don't? What it's unique
       | benefit?
        
         | brightball wrote:
         | I believe it's the functional language option on top of .NET.
         | From what I understand, it's a pretty well designed one too.
         | 
         | I don't work in the .NET ecosystem, but I know if came up a lot
         | when I was getting into Erlang/Elixir.
        
         | mjul wrote:
         | Type providers are novel.
         | 
         | It is a mechanism to provide type safe access to structured
         | data and data services with almost no code. It feels like
         | magic.
         | 
         | Like other ML-derived languages (F# is an OCaml dialect) it has
         | algebraic data types and pattern matching to make code simple
         | and complete without missing edge cases.
         | 
         | Also, it is arguably the best functional language on .NET, so
         | it has a great platform with a large ecosystem to build on. And
         | the tooling is great (Jetbrains, Microsoft IDEs).
        
           | aloisdg wrote:
           | > it is arguably the best functional language on .NET,
           | 
           | it is also the only real one. On .NET we have C#, C++ and
           | vb.net then there are some other fringe langs like IronPython
           | or IronRuby and I think there is a PHP one too.
        
             | aloisdg wrote:
             | I forgot Boo and Nemerle. They are quite niche languages
             | though.
        
           | runevault wrote:
           | I haven't done as much as I would like with them, but I feel
           | like until someone tries type providers they don't get just
           | how powerful they are. Being able to point to an example .csv
           | file and have it generate the classes for you, and update
           | them if you change said format, in a way that it ensures the
           | types still work, is amazing. And you can do it for ANYTHING
           | as long as you have a way to extract the data to feed it to
           | the compiler.
           | 
           | I still need to learn how to write a type provider just so I
           | can.
        
         | DeathArrow wrote:
         | Functional, readable, easy to learn, as performant as C#, has
         | the benefit of huge .NET ecosystem of libraries.
        
         | enricosada wrote:
         | For me is that pratically every time, if compile, it works.
         | 
         | It's really easy to express a domain (with discriminated union
         | and type) and the defaults (immutability, option, removal of
         | boilerplate, high order function to manipulate data, structural
         | comparison not reference) allow me to write correct code, who
         | is readable without too much friction.
         | 
         | Support a repl as first class, so that works too if you like
         | repl driven development
         | 
         | Community is also nice
        
         | de_keyboard wrote:
         | It's the _combination_ of features which is killer. I don 't
         | know of another language that offers all of these:
         | 
         | - Expression orientated
         | 
         | - Lightweight syntax
         | 
         | - Emphasis on immutable data and pure functions
         | 
         | - do-notation (in F# these are called Computation Expressions)
         | 
         | - Type-safety without _too_ many annotations (global type-
         | inference)
         | 
         | - Mainstream ecosystem of libraries (in this case .NET)
         | 
         | - Compile to JavaScript
        
           | KurtMueller wrote:
           | Units of measure is also very cool!
        
         | Smaug123 wrote:
         | It's just really pragmatic about the upsides of functional
         | programming. It describes itself as "functional-first", but
         | isn't afraid to fall back on OOP in situations where OOP really
         | does model the situation better.
         | 
         | In my mind, it's taken the easiest 80% of the features of a
         | true functional language, but then picked a pragmatic point at
         | which to stop; the result is a language which is easy to learn
         | and also makes it easy to use "most" of the good things you
         | want from a functional language.
        
       | barrenko wrote:
       | When I learn Haskell, I'll be lot closer to God.
        
       | StreamBright wrote:
       | F# has become my default goto language. It is absolutely amazing
       | to create cloud services in it an I have a small ETL tool as
       | well. I would not trade it for anything else.
        
       | jgwil2 wrote:
       | Link to _What I wish I knew when learning Haskell_ is broken
       | because it has https. The correct link is
       | http://dev.stephendiehl.com/hask/ in case anyone was looking for
       | it.
        
       | AlbertCory wrote:
       | That it's the same as Gb (on a piano or fretted instrument)?
       | 
       | (Sorry. Couldn't resist.)
        
       | AtNightWeCode wrote:
       | In my area there was a huge push for functional programming and
       | F# some years ago. A long time ago since I heard anybody working
       | with F#. Clojure is somewhat popular though in fintech.
       | 
       | Functional programming is something I think one should learn
       | cause the concepts are useful in other programming languages too.
       | Over time what is useful in functional programming languages will
       | be available in other languages. In fact, a lot already is.
       | Functional programming is not an USP in my world.
       | 
       | When I started with C#, code bases were full of GoF patterns, if
       | and switch statements were banned, there were hierarchies of
       | inheritance, there were states spread out and encapsulated
       | everywhere, static functions were banned. Today, code bases are
       | mostly stateless except for things that needs to be reused, there
       | are pure functions everywhere, inheritance is mostly used in
       | libraries and where interfaces can't be used (yet), switch is ok
       | and pattern matching is around the corner in several languages.
       | 
       | More unpopular opinions. Immutability is overrated. In some
       | programming styles, in some old languages there was a high risk
       | of changing something by accident. Typical cause people did not
       | know if they were working on a reference or a copy. Also, it was
       | common to change fields on purpose. This problem does not really
       | exist in a lot of programming languages today. But I do wonder if
       | Go coders code benefit from some more immutability.
       | 
       | I think the future of F# looks very dark but the functional style
       | of programming will for sure have its place. What could change
       | this is if F# really excels in some area like Go have done.
        
       | vasergen wrote:
       | I wish I have Elixir with types like in F#
        
         | Rapzid wrote:
         | I wish F# had a project comparable to Phoenix to boost its
         | visibility.
        
       | 7thaccount wrote:
       | The biggest for me is needing to understand the .NET ecosystem
       | without knowing C#. Then there's the lack of beginner
       | information. I own several F# books and none of them assume
       | you're coming from a scripting language background. I eventually
       | gave up for good. OCaml doesn't have the .NET problem, but I
       | found it to be unergonomic in a lot of ways.
       | 
       | Make no mistake, it's a cool language that I'd love to be good
       | at. The code always looks elegant, I'm just terrible at writing
       | it.
        
         | devmunchies wrote:
         | I had the exact same problem. Even all the http servers had a
         | lot of .net boilerplate to get started. A lot of that should be
         | abstracted. I built an http server library that abstracts the
         | .net parts. https://wiz.run/
         | 
         | The hello world server:                 open Wiz.Server
         | open Wiz.Context       open Wiz.Route            let myHandler
         | ctx =         ctx |> sendText "Abra Kadabra Kalamazoo!"
         | let myRoutes = [         get "/" myHandler       ]
         | genServer()       |> setRoutes myRoutes       |> run
        
           | devmunchies wrote:
           | thinking more about it, F# needs to appeal to non-dotnet
           | developers and other developers looking for a functional
           | language for real workloads.
           | 
           | F# currently seems easiest for c# dev to get started, but c#
           | devs have almost no incentive to do so.
        
             | SBArbeit wrote:
             | I could say the same thing about any language. For
             | instance:
             | 
             | "Python needs to appeal to C# developers and other
             | developers...
             | 
             | Python seems easiest for PHP devs to get started, but C#
             | devs..."
             | 
             | And, the truth is, no, Python doesn't need to do that at
             | all. It just has to be the best Python it can be.
        
               | xhevahir wrote:
               | Using Python doesn't require you to learn a (big) second
               | language before you can do anything useful, though. F#
               | arguably does. Maybe that is the best F# that F# can be.
               | Which, for a lot of people, is not good enough.
        
         | DeathArrow wrote:
         | There are several good books like:
         | https://www.amazon.com/Stylish-Crafting-Elegant-Functional-C...
         | and https://www.amazon.com/Get-Programming-guide-NET-
         | developers/... and also some courses on Udemy like:
         | https://www.udemy.com/course/fsharp-from-the-ground-up/ and
         | https://www.udemy.com/course/hands-on-f-application-developm...
         | 
         | Also there are lots of learning resources here:
         | https://fsharp.org/learn/ some for guys coming from scripting
         | languages like Python. As a matter of fact, F# can be used for
         | scripting, too.
        
           | 7thaccount wrote:
           | I'm not saying that you can't write an F# script, but that
           | the path to getting one written is not obvious to those
           | coming from scripting languages that are much simpler than
           | the VAST .NET & JVM ecosystems. There is always some bizarre
           | .NET arcana that gets in the way.
        
         | orra wrote:
         | Ah, that's interesting.
         | 
         | I'm a huge fan of F#, but I had the advantage of knowing .NET
         | first.
        
         | barrenko wrote:
         | Kinda agree, but F# works much better for me with my knowledge
         | of .NET than e.g. Clojure with my understanding of Java.
         | 
         | It's a cliche saying, but for me F# just works! (tm)
        
         | Decabytes wrote:
         | This was my issue when trying to learn clojure as well
        
           | billfruit wrote:
           | Yes, my experience as well. Clojure is more "lisp for java
           | programmers" than "java for lisp programmers".
           | 
           | Most of introductory material I found was good in explaining
           | functional concepts, lisp approach to solving problems etc,
           | but I thought assumed a working knowledge of the JVM
           | ecosystem.
           | 
           | For someone utterly unfamiliar to Java/JVM world would find
           | clojure extremely baffling, cryptic error messages, needing
           | to be familiar with the rather large java standard library,
           | etc.
        
           | 7thaccount wrote:
           | Same. F#, Clojure, Scala, & Kotlin have all been the same for
           | me. Python's VM is written in C, but I have no reason to know
           | C. In Clojure they have you call out to Java libraries a ton.
           | Someone always tells me that this isn't true on here, but it
           | was my experience as well. Having to learn so many tools like
           | emacs or CIDRE or Leinegen was also a turn off.
        
             | gorjusborg wrote:
             | I really love Clojure, but I have a lot of experience on
             | the JVM so I didn't have to climb multiple learning curves
             | simultaneously.
             | 
             | While the clojure ecosystem has a lot of wonderful, bright
             | and helpful people in it, and clojure itself is technically
             | impressive (esp. its collections implementation), the new
             | user experience isn't great.
             | 
             | I'm not an experienced emacs user, so that makes it doubly
             | difficult, as the ironed-out workflows seem to assume that
             | you are (which is fair, as emacs and lisp are like peanut
             | butter and jelly). However, these days it's fair to assume
             | that a new clojure user is probably learning 'clojure',
             | 'lispy ways', 'java/jvm', and 'emacs' simultaneously.
             | 
             | I think that calva/vscode has a lot of potential to drop
             | emacs off that list, which is welcome, as its learning
             | curve alone is legendary. If you look at that list, it
             | should not be surprising that the community is small.
             | There's so much to learn that I it seems too much to even
             | start.
        
               | kaliszad wrote:
               | There are multiple options to approach the Clojure*
               | ecosystem. But yes, it is more focused towards dedicated
               | and experienced developers overall. I use IntelliJ Idea +
               | Cursive for development and that seems quite comfortable.
               | I have a very rough sketch of the environment setup for a
               | real app here: https://www.orgpad.com/s/hfxYQYkcLYV We
               | use a similar setup to develop OrgPad itself.
               | 
               | You can use Babashka https://github.com/babashka/babashka
               | for a quick and dirty setup to get you up and running
               | quickly. That is also useful for scripting some things.
               | You might also try shadow-cljs + ClojureScript, if you
               | are more at home in the Node.js/ Browser JavaScript
               | ecosystem and want to do something with it. There is a
               | new "(Not)Babashka" but built on ClojureScript:
               | https://github.com/borkdude/nbb that might be interesting
               | as well.
               | 
               | I have found this video by James Trunk:
               | https://youtu.be/C-kF25fWTO8?t=848 to have a very nice
               | live coding example.
        
               | barrenko wrote:
               | Clojure is pretty cool, but I've come to understanding
               | that as a beginner I would have been better off just
               | learning good old Lisp.
        
             | dboreham wrote:
             | Haskell doesn't call out to anything.
        
           | pjmlp wrote:
           | That is the issue with any guest language, because it is
           | impossible to hide the platform, unless the language is so
           | constrainted that is practically useless.
           | 
           | It is a hard to swallow truth, but guest languages really
           | require understanding of the underlying platform.
           | 
           | Another example, no matter one's opinion on C or JavaScript,
           | mastering them is a much more confortable life on UNIX/POSIX
           | platforms and browsers than trying to pretend they aren't
           | there.
        
             | 7thaccount wrote:
             | Agreed. I think you say it more succinctly.
             | 
             | It can also be frustrating if you know a little OO (but not
             | how Java does everything) and then try to learn a
             | functional language that sits on top of one of these OO tar
             | pits of an ecosystem. I can write Python classes, but
             | seeing the complicated mess of Java is frustrating as that
             | has to be learned as well. Nothing against Java btw (it has
             | its place), but it does seem to require a lot of
             | boilerplate.
        
               | mumblemumble wrote:
               | First off -- I don't really want to get into bickering
               | about Java is OO or not.
               | 
               | That said:
               | 
               | I think that Java is best understood as an enterprise
               | programming language, not as an object-oriented one.
               | 
               | There's a very peculiar class of programming languages
               | that are a product of a specific period of history. At
               | the time, companies were looking for ways to scale beyond
               | the limits of the then-dominant procedural programming
               | paradigm. But they had a lot of existing investment in
               | it, and so teams were naturally hesitant to abandon it
               | entirely.
               | 
               | This situation created an ecological niche that allowed a
               | very peculiar class of programming language to take root.
               | Java and C++ are the best-known examples, but there were
               | others such as Objective-C. C# and Visual Basic.NET are
               | probably the last notable examples. These were multi-
               | paradigm languages that layered object-oriented features
               | on top of procedural bones. Earlier examples such as C++
               | and Objective-C made this quite explicit, and were likely
               | to even have their atomic types not be objects. Later
               | examples eliminate some features such as non-object types
               | and global functions and variables, but still retain much
               | of their procedural heritage if you know what you're
               | looking for. Probably the most notable one here is a
               | tendency to favor explicitly state-oriented idioms over
               | properly encapsulating state.
               | 
               | Java falls somewhere in the middle. It has later features
               | like full-fledged garbage collection, but lacks others
               | such as a consistently object-oriented type system.
               | 
               | I think that its tendency toward boilerplate directly
               | reflects its stage in this evolution. Basically, what we
               | perceive as boilerplate is really a hold-over from how
               | procedural languages tended to be generally less
               | declarative - it was up to the programmer to handle a lot
               | more stuff for themselves.
        
           | rixkys wrote:
           | I'm surprised, I found clojure even while I was a pretty much
           | total beginner programmer fairly easy to get into, via
           | clojure for the brave and true at least was very good for
           | getting the basics.
        
             | WillPostForFood wrote:
             | Clojure for the brave and true shows the exact problem.
             | 
             | Chapter 1: install and learn the JVM
             | 
             | Chapter 2: Emacs
             | 
             | Chapter 3, finally start learning Clojure if you made
             | through the first two chapters. Those first two chapters
             | are going to filter out quite a few potential Clojure
             | learners.
        
             | 7thaccount wrote:
             | Even that involves downloading and installing a fair amount
             | of build tool stuff which may be necessary, but just drove
             | me away.
        
         | phillipcarter wrote:
         | There's definitely room for a book or blog series along the
         | lines of "F# for python programmers" or something.
         | 
         | Unfortunately there's some level of .NET tooling you need to
         | understand before you can do much today, and several .NET
         | concepts creep in with that.
         | 
         | The good news is that .NET Interactive is shaping up to be a
         | great way to avoid most of that. At least so far all you need
         | to do is install the .NET SDK, then install a VSCode plugin and
         | you're good to go - just write code like you would in a python
         | notebook, and acquiring packages is even easier than in Python:
         | https://github.com/dotnet/interactive#notebooks-with-net
        
           | dharmaturtle wrote:
           | Linking your demo of VS Code Notebooks cause it was great:
           | https://youtu.be/_QnbV6CAWXc?t=1298
        
       ___________________________________________________________________
       (page generated 2021-10-14 23:01 UTC)