6 ms·
So...I think a decent choice to make here is to switch from OCaml to F#. You'll get almost all of the benefits and most of the drawbacks go away. And for the mo
by darksaints 6y ago
So...I think a decent choice to make here is to switch from OCaml to F#. You'll get almost all of the benefits and most of the drawbacks go away. And for the most part, you can directly translate the code from OCaml to F#.
The big reason to not use F# vs OCaml tends to come down to the lack of functors... but it looks like your current codebase might not be using them much.
- Nuzzerino 6y ago> The big reason to not use F# vs OCaml tends to come down to the lack of functors... What do you mean by that? F# has support for functors, or are you referring to something else? https://fsprojects.github.io/FSharpPlus/applicative-functors.html https://fsprojects.github.io/FSharpPlus/applicative-functors...
- darksaints 6y agoThose are an implementation of functors as they exist in Haskell. The functors I'm talking about are actually a language level construct that is a primary abstraction mechanism in OCaml/SML. They are essentially higher-level modules: modules that are parameterized by other modules. https://stackoverflow.com/a/16353711 https://stackoverflow.com/a/16353711
- pmoriarty 6y agoCan someone explain to me like I'm 5 what the big deal about functors is?
- darksaints 6y agoProbably not, as it is a very abstract generalization for what is essentially a simple concept that for most purposes doesn't need a math-y abstraction. And it would depend on whether you're talking about Haskell, or OCaml, or Category theory. The best I could describe the general concept is that a functor allows you to take something of some type and maps it to another type via some unspecified function.
- yawaramin 6y agoIf you mean ML (i.e. OCaml) functors, then to put it simply: they are the primary code abstraction mechanism in ML. ML doesn't have inheritance and runtime dispatch, instead it uses functors which do static dispatch. Simple example: in an OOP language you might have a Map<K, V> class for any type K, V where K must be an instance of an Ordered interface so that the map implementation can do efficient lookup. In OCaml, you have a Map.Make(Ord : Ordered) functor which explicitly takes a module Ord as its parameter. The Ord module implements the key data type, which must support the Ordered interface. When you (statically) apply the functor, you get back a new module which specializes a map data type to work for the specific key type. E.g., module StringMap = Map.Make(String) The String module implements the Ordered interface, so it can be used as the argument here. Now you can create and manipulate maps of strings to any values. You might be wondering, what's the payoff? It's very similar to the payoff for interfaces--code abstraction. It's just that it's all statically resolved and highly efficient.
- siwatanejo 6y agoSounds like this is covered by F# already, simply by the use of genercs (similar to what you described for OOP, which in that particular case doesn't really have any OOP downsides, i.e.: no inheritance, no state).
- ernst_klim 6y ago>simply by the use of genercs It depends on what you mean by "generics". Functors are generics, but very powerful ones, akin to packages in Ada. They are way more generic than what parametric polymorphism allows you to do in F#, they support Higher Kinded Types, module can have many type variables within it etc etc.
- Paradigma11 6y agoIn F# you have List<'a> but you cant have a single map operation abstracting over Lists, Arrays, Options..... so they have to be implemented separately Option.map, Array.map.....
- yawaramin 6y ago
- nukifw 6y agoHe's talking about functor from OCaml and SML which are basically a function in the module level. So a module which take other modules as arguments and produce a new module.
- tikhonj 6y agoIn OCaml, "functors" are parametrized modules—mostly unrelated to functors and applicatives in the Haskell sense. Think about it as a module that can take another module as an input.
- mc10 6y agoOCaml functors are not the same as Haskell/F# functors/applicatives (which are essentially one and the same in OCaml if you use named arguments). Instead, they're roughly "functions from modules to modules": https://dev.realworldocaml.org/functors.html https://dev.realworldocaml.org/functors.html. Functors allow you to replicate much of what classes/objects in an OO language offer, but with static instead of dynamic dispatch.
- ojnabieoot 6y agoI am an F# person rather than OCaml and am not familiar with the compiler, but this seems to be overstating the difference: I thought the OCaml functors are “real” mathematical functors that implemented a structured type polymorphism over the “input type” - they look pretty similar to C++ templates superficially but they work similarly to Haskell type classes. They are “functions from modules to modules” but those functions take types as values. Real experts should let me know if I am mistaken: I don’t think OCaml and Haskell have strictly the same type system, but they are both similarly more expressive than F# because of this specific type -> type polymorphism that in particular lets you do type-checked monads, etc.
- didibus 6y agoNeither Haskell's nor OCaml's functors are the same as the mathematical one I believe, but both are similar in some way that the word makes sense to be used for their respective feature. In OCaml, functors map between an abstract module and some concrete one. And in Haskell functors are structures that can have a function that maps over their elements. In math a functor is a map between categories. So you can see how all three kinda make sense as functors, but also are different in exactly what they are.
- tome 6y agoBoth Haskell's and OCaml's functors are special cases of the general mathematical one.
- 6y ago
- karmakaze 6y agoI was thinking the same thing. Using multicores and having a library ecosystem (through interop rather than conventional F#) should be a win. I don't have an idea what performance difference to expect but certainly closer to OCaml than Python even for single-core.
- darksaints 6y agoAt least as of a couple years ago, OCaml wins on performance for anything single core, but not by much. F# is usually within a 5-10% performance gap. Absolutely better than Python.
- pbiggar 6y agoI don't think that's accurate. The Benchmark game [1] shows F# winning more and by larger margins. My own benchmark [2], which was reimplementing Dark in three languages, had F# with 2x the throughput. (standard caveat that benchmarks suck) [1] https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/ocaml.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/... [2] https://github.com/darklang/fizzboom/issues/13 https://github.com/darklang/fizzboom/issues/13
- darksaints 6y agoInteresting, they have definitely closed a lot of gaps since I last used it.
- pbiggar 6y agoI think .NET Core (esp v5) has had lots of good performance work: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/ https://devblogs.microsoft.com/dotnet/performance-improvemen...
- banashark 6y agoI enjoy f# a lot, but it doesn't necessarily help with all of their problems. One of the biggest problems they mention is with postgres. F# has a postgres problem as well. Your options in f# for postgres usage include the following high-level categories: • Dapper/RepoDb/Other community libs • Typeprovider based like Fsharp.Data.Npgsql • EF core (where you build the fsharp design-time support yourself) • Using C# in another project as a database interaction abstraction I've had to mix and match for the projects I've worked on because I've had trouble finding a single library where: 1) Joins are supported in a sane way 2) Batch inserts work 3) Interacting with native features (views, functions, SET variables) works 4) It's still in fsharp It's not bad, but when I work on $DAYJOB projects in Typescript/etc where database access is smooth, I wonder how long it might take to rewrite for the database heavy projects. Also should mention that I'm very thankful for the libraries that _do_ exist, and the effort put into making them as feature as they are. It's just one of the areas that I don't think is a strength of F# right now.
- darksaints 6y agoBut those are all database abstraction mechanisms or ORMs. Regular SQL access to postgres databases is pretty much a fully solved problem in F#, even if the ORMs are not.
- banashark 6y agoThis is true (with the caveat of some interesting edge-cases with npgsql and F#), however the next paragraph in the article mentions "a lack of a high-level, production web stack". Definitely a personal take here, but since I've worked for a while with postgres, a "high-level, production web stack" for me is something that has an established, good DX way to work with this popular database. Managing ADO.NET connections, working around the type systems and writing a lot of mapping/connecting code are all things that don't solve my business problem. While not prolific, I've written a handful of production web applications in F# (Suave, Giraffe, Saturn, and Razor Pages) as well as other stacks, and have found a hybrid approach that works for my concerns, but I've found a comprehensive solution not as simple as other ecosystems.
- loxs 6y agoI tried doing that for my program and failed miserably, mostly because CLR is not optimised the same way the OCaml runtime is optimised to minimise copying of memory. As a result the (direct translation of the) program became more than 5 times slower, which was a deal breaker for this use case. Yes, there are ways to write it in a .NET-y way in F#, but then it requires a "complete" rewrite and F# gives no real benefits with "being similar". In contrast, after that I migrated to Rust and I am delighted. I wrote about it here: https://news.ycombinator.com/item?id=24893285 https://news.ycombinator.com/item?id=24893285 Of course, this is also a full-rewrite without using the same idioms as in OCaml (mostly because I mutate objects directly when needed) but I still think it's much better than F# as the language (Rust) is miles ahead in the practicality domain. Indeed, it's much better than anything I've seen so far. And still so very much "functional" and "elegant". I just miss the transparent currying from OCaml.
- ernst_klim 6y ago> You'll get almost all of the benefits and most of the drawbacks go away. That's a bit overstatement. You can call .Net code from F#, just like you can call Java from Clojure or Python/Rust/C from OCaml. It just would be foreign and unidiomatic (hello, null pointers, methods, OOP). And you can call C/Python/Rust from OCaml, we made quite a lot of wrappers for Gstreamer and some Rust libs in OCaml and it was quite painless. So it's a bit of simplification, you can call foreign code in OCaml, it's not that much harder than F# considering there are higher level FFIs for C, Rust and Python available. Author could just use these as well.
- dfgdghdf 6y agoWriting an F# wrapper for a C# API is considerably less involved than writing an OCaml wrapper for a C API. This is because F# and C# share: * build tools * package management * garbage collector * base types (string, int, etc). The F# type-checker understands C# types, so you know that you are consuming the C# API correctly (at least at the type-level). F# can be be used as a new syntax for C#, if you wanted to go that way.
- akra 6y agoMore interestingly you can also go the other way if you use only the lower level F# features (F# being mostly a superset of C# features) and a C# developer won't realise that they are calling F# code - it's all just .NET IL in the end. Did it often when creating libraries at work; it isn't like invoking another language's binary code at all. One of the pro's I guess of working with a VM (JVM/.NET) based language - interop between languages is usually much easier and so niche languages can have a much larger ecosystem than they otherwise would have.
- angio 6y agoI was thinking the same all throughout the reading. I've been using F# on GCP in production for 3 years now and it's fantastic and only getting better. You can leverage existing .NET libraries (for example, you get official GCP libraries from google) and if you use them enough it's easy enough to write a functional wrapper around them. I recently rewrote the frontend using Fable.React so that I can share code between backend and frontend.