It's cool to see a link about learning OCaml so high on HN. I started teaching myself OCaml a few months ago and I really like it. Here's a few things I like so far and why I think anyone that uses Go or Rust should give OCaml a look:
1. OCaml compiles to a binary like Go and Rust do
2. The type system is helpful without being a huge burden on learning/productivity (unlike Rust and Haskell)
3. Garbage collection
4. Pattern matching and algebraic data types (like Rust)
5. OCaml is plenty fast at CPU bound work(slower than Rust, faster than Go) despite not being parallel (yet)
Those are my takeaways of what I enjoy about OCaml so far. It has been the most approachable typed functional language that I've looked at yet! Depending on the type of things you want to learn and problems you want to solve, Your Mileage May Vary.
My power combo is F# and Rust. F# is fairly fast, has great tooling and rather expressive. And for the parts I need the speed, Rust fits in nicely. I can keep safety, while maintaining decent expressiveness. Something like Rust is needed, because when you need manual memory control, you really need it. With F#, I could measure the impact of every single allocation, even though short lived GC items are cheap.
>1. OCaml compiles to a binary like Go and Rust do
And Haskell.
>2. The type system is helpful without being a huge burden on learning/productivity (unlike Rust and Haskell)
What? The type system is partly why my coauthor can use Haskell, unlike JS or Java. Haskell was her first time ever programming and now she's teaching Haskell to her 10 year old son.
I use Haskell in my day job, I couldn't do my job without the type system!
So in terms of learning and productivity in Haskell (can't speak for Rust), I will strongly disagree here.
The rest of the points apply for Haskell as well.
Haskell doesn't need to be hard to learn at all, it hasn't had the learning resources it deserves and expectations weren't being set properly. It's more like learning a new way to program (functionally) rather than a dialect of an existing paradigm (imperative, but we give you a map and a reduce function).
That paradigm (functions alone) is very simple but the implications are non-obvious and require a method of introduction that involves a lot of exercises.
This is also great cheat sheet for someone still getting used to the OCaml syntax.
I usually advise people to pretend that double semicolons don't exist for anything but the interactive top level. In source files, you can forget about double semis entirely as long as you just remember to always assign the result of an imperative statement to the dummy "_" name.
let _ = print_string "hi"
Then you can think of ;;<enter> as merely a fancy way of hitting the return key in the interactive REPL. There's also a way to use a different key mapping (control+enter) instead of ;; in utop, so there would be no reason to even acknowledge the existence of double semis.
https://github.com/diml/utop/issues/131
This is one thing I'm on the fence about F# doing "better", double semis are replaced by requiring you do something with your result, either assigning the result of piping it to the "ignore" builtin.
im quite amazed that ocaml seems to be on a rise (judging from how often i've recently seen it on here). it reminds me of the time i started to dig into it more than a decade ago when mldonkey [0] was a thing.
also, this is the way to briefly introduce a programmer to a new language. just show the commented syntax. i just hate reading all the prefaces and texts of language manuals. it's good they're there but i'm just loosing interest too quickly if you don't show me code.
It seems `int_of_float` and `float_of_int` are deprecated by the Jane Streets Core library. It even throws errors on utop. I believe they need to be replaced by `Int.of_float` and `Float.of_int` respectively.
EDIT: Some more corrections:
1. `List.hd []` doesn't raise an error as its return type is an option. So the result is a `None`.
2. `List.map` and `List.filter` arguments should be reversed. First argument should be a list and the second should be the mapping function.
The code examples doesn't use Jane Streets Core as the primary standard library. If you do, for example by adding `open Core.Std` to your .ocamlinit, you'll get the behaviour you're describing.
It is probably a good idea to use Core, but for this introduction I wanted as little requirements as possible.
I do really like OCaml, although Rust is the one I'm starting to look to where in the past I'd consider OCaml (yes, two different languages, but similar in practical function approach and safety).
The one things that I absolutely can't stand about OCaml is the lack of an easy, available, include-in-the-standard-library, debugging function. Every damn time I work with OCaml, I end up having to write annoyingly time-consuming "print_blah_blah" functions to handle debugging. And such a debugging feature should handle errors already, and not return the Option type. I shouldn't have to write a function to handle errors on a debugging statement.
And yes, I'm sure there are some nice versions of this already available in 3rd-party libraries, but this should be in the standard library.
It's easy to get a quick comparison by searching stackoverflow so I won't reitterate those answers, but I would just mention a couple of my favorite things from OCaml that F# doesn't have that those answers tend to leave out:
- Polymorphic variants
- GADTs
- Named arguments (that are still curried if you can believe it!)
- Last time I checked OCaml had better record label scoping. F# doesn't allow two record types in scope that share a record label name. Does anyone know if F# has plans to implement what OCaml has (or have they already?) OCaml used to have the same problem but it was fixed and now dealing with OCaml records has been massively improved as a result.
I'm mostly only experienced with F#, but it has a few features that OCaml doesn't (type providers, units of measure, computation expressions) and is missing a few that OCaml has (functors). F# has a bit of a cleaner syntax in some ways IMO[0], but that's offset by .NET interop - the standard libraries are pretty much all borrowed from C#, and therefore tend to be more OO-first than functional-first.
Also, because it runs on .NET/Mono, you can do multicore stuff in F# very easily, whereas OCaml's multicore support is very immature (and actually not present at all until the next release, 4.03).
I would not actually compare them from language point of view but ecosystem point of view - but then again, I like simplistic stuff. Give me algebraic datatypes, pattern matching and type inference and I'm happy.
That said, F# in my opinion benefits hugely from the Visual Studio tooling (if one can use it). The main benefits for me are:
- the integrated F# command line facilitates pretty much similar development as with lisps - one can instantiate a context, and then develop ones program code at the same time as the context is live. With static types. I.e. create a function, interpret in repl, run function, observe the side-effects etc. Once done compile. Then load dll in repl, build new functionality on top of previous module etc etc.
- Visual Studio intellisense debugs my logic as I type it. Having the IDE proofreading my sources as I type it is a huge productivity win. Of course, if the program logic is built around types, that is - but with F# this is the easiest way to write stuff any way.
- This is a fringe issue but one can write Unity scripts in F# :)
Concurrency is not built-in, you can get monadic concurrency from libraries (either lwt or Async). There is no parallelism support yet, but multicore support should be there by the end of the year.
rubiquity|10 years ago
1. OCaml compiles to a binary like Go and Rust do
2. The type system is helpful without being a huge burden on learning/productivity (unlike Rust and Haskell)
3. Garbage collection
4. Pattern matching and algebraic data types (like Rust)
5. OCaml is plenty fast at CPU bound work(slower than Rust, faster than Go) despite not being parallel (yet)
Those are my takeaways of what I enjoy about OCaml so far. It has been the most approachable typed functional language that I've looked at yet! Depending on the type of things you want to learn and problems you want to solve, Your Mileage May Vary.
steveklabnik|10 years ago
MichaelGG|10 years ago
coolsunglasses|10 years ago
And Haskell.
>2. The type system is helpful without being a huge burden on learning/productivity (unlike Rust and Haskell)
What? The type system is partly why my coauthor can use Haskell, unlike JS or Java. Haskell was her first time ever programming and now she's teaching Haskell to her 10 year old son.
I use Haskell in my day job, I couldn't do my job without the type system!
So in terms of learning and productivity in Haskell (can't speak for Rust), I will strongly disagree here.
The rest of the points apply for Haskell as well.
Haskell doesn't need to be hard to learn at all, it hasn't had the learning resources it deserves and expectations weren't being set properly. It's more like learning a new way to program (functionally) rather than a dialect of an existing paradigm (imperative, but we give you a map and a reduce function).
That paradigm (functions alone) is very simple but the implications are non-obvious and require a method of introduction that involves a lot of exercises.
Veedrac|10 years ago
On what basis do you say this? I'm not claiming to know the answer, but the (terrible) internet benchmarks I can find put them roughly neck-to-neck.
jordwalke|10 years ago
I usually advise people to pretend that double semicolons don't exist for anything but the interactive top level. In source files, you can forget about double semis entirely as long as you just remember to always assign the result of an imperative statement to the dummy "_" name.
Then you can think of ;;<enter> as merely a fancy way of hitting the return key in the interactive REPL. There's also a way to use a different key mapping (control+enter) instead of ;; in utop, so there would be no reason to even acknowledge the existence of double semis. https://github.com/diml/utop/issues/131snuxoll|10 years ago
mercurial|10 years ago
glasz|10 years ago
also, this is the way to briefly introduce a programmer to a new language. just show the commented syntax. i just hate reading all the prefaces and texts of language manuals. it's good they're there but i'm just loosing interest too quickly if you don't show me code.
[0] https://en.wikipedia.org/wiki/MLDonkey
ignoramous|10 years ago
amirmc|10 years ago
http://ocaml.org/learn/books.html
arocks|10 years ago
EDIT: Some more corrections:
1. `List.hd []` doesn't raise an error as its return type is an option. So the result is a `None`.
2. `List.map` and `List.filter` arguments should be reversed. First argument should be a list and the second should be the mapping function.
fredyr|10 years ago
It is probably a good idea to use Core, but for this introduction I wanted as little requirements as possible.
edit: spelling
jnbiche|10 years ago
The one things that I absolutely can't stand about OCaml is the lack of an easy, available, include-in-the-standard-library, debugging function. Every damn time I work with OCaml, I end up having to write annoyingly time-consuming "print_blah_blah" functions to handle debugging. And such a debugging feature should handle errors already, and not return the Option type. I shouldn't have to write a function to handle errors on a debugging statement.
And yes, I'm sure there are some nice versions of this already available in 3rd-party libraries, but this should be in the standard library.
freditup|10 years ago
jordwalke|10 years ago
- Polymorphic variants
- GADTs
- Named arguments (that are still curried if you can believe it!)
- Last time I checked OCaml had better record label scoping. F# doesn't allow two record types in scope that share a record label name. Does anyone know if F# has plans to implement what OCaml has (or have they already?) OCaml used to have the same problem but it was fixed and now dealing with OCaml records has been massively improved as a result.
Arcsech|10 years ago
Also, because it runs on .NET/Mono, you can do multicore stuff in F# very easily, whereas OCaml's multicore support is very immature (and actually not present at all until the next release, 4.03).
[0] See https://msdn.microsoft.com/en-us/library/dd233199.aspx The "verbose" syntax is almost exactly OCaml, the "Lightweight" syntax is what's commonly used in F#.
fsloth|10 years ago
That said, F# in my opinion benefits hugely from the Visual Studio tooling (if one can use it). The main benefits for me are:
- the integrated F# command line facilitates pretty much similar development as with lisps - one can instantiate a context, and then develop ones program code at the same time as the context is live. With static types. I.e. create a function, interpret in repl, run function, observe the side-effects etc. Once done compile. Then load dll in repl, build new functionality on top of previous module etc etc.
- Visual Studio intellisense debugs my logic as I type it. Having the IDE proofreading my sources as I type it is a huge productivity win. Of course, if the program logic is built around types, that is - but with F# this is the easiest way to write stuff any way.
- This is a fringe issue but one can write Unity scripts in F# :)
ode|10 years ago
Thanks
mercurial|10 years ago
steveklabnik|10 years ago