Yeah to clarify, let is required for defining any named function, rec is required for any recursive function. If you try to write a recursive function without the rec keyword, you’ll get a compile time error of “functionnamehere is not defined”.
Implicit parameters are mainly used for implementing typeclasses. It would be great to have a comparison between Scala implicits, Haskell typeclasses, and F# “computation expressions” (and maybe throw in the OCaml “modular implicits” feature proposal).
Underscores are great.
Tail-recursion in Scala is unfortunately very limited (since it’s just done by the compiler rewriting the function). I don’t know what F# has in that regard.
Call by name is a pretty minor feature IME. It makes it easier to add custom control-flow-like syntax. IMO it’s probably not worth the overhead of dedicated syntax.
It’s worth saying that traits are a limited form of multiple inheritance that avoids the biggest problem by forcing each class to inherit from exactly one class with a constructor. Nothing is minor and useful.
While it’s true that there’s nothing at the language level to force good code structure practice, multi-module projects with maven or the like are a very common practice (even quite small libraries are often split into several modules).
It would be great to have a comparison between Scala implicits, Haskell typeclasses, and F# “computation expressions”
That last one is very different; F# computation expressions are “just” monads, repackaged in more mainstream vocabulary and with a slightly more explicit syntax. I think Microsoft was brilliant for giving them a different name (though I still honestly wish they’d just kept them called “workflows”, which was even less scary.)
Tail-recursion in Scala is unfortunately very limited (since it’s just done by the compiler rewriting the function). I don’t know what F# has in that regard.
The CLR can do full tail recursion; F# as a language requires recursive functions be tagged as such for namespace reasons (exactly like OCaml), but the CLR itself can do full-blown TCO out-of-the-box.
It’s worth saying that traits are a limited form of multiple inheritance that avoids the biggest problem by forcing each class to inherit from exactly one class with a constructor. Nothing is minor and useful.
I don’t think the author was really complaining about traits, as much as complaining about Scala’s use of them in the stdlib. F# does lack them, but they’ve always seemed less necessary to me there, perhaps due to runtime generics letting me use normal polymorphism to get similar benefits.
Computation expressions are better described as syntactic sugar for monads, so that nested binds and returns can be shown more intuitively (and compactly).
let maybe = new MaybeBuilder()
let sugared =
maybe {
let x = 12
let! y = Some 11
let! z = Some 30
return x + y + z
}
…. is equivalent to
let maybe = new MaybeBuilder();
let desugared =
maybe.Delay(fun () ->
let x = 12
maybe.Bind(Some 11, fun y ->
maybe.Bind(Some 30, fun z ->
maybe.Return(x + y + z)
)
)
)
Tail call optimization in F# is handled implicitly. If the recursion is the last part of the function it will optimize.
You still need
let rec
in the first place though, don’t you?You need
let rec
in order for the function to be able to call itself, so it’s impossible to forget to add that part. But yes, you do need it.Yeah to clarify, let is required for defining any named function, rec is required for any recursive function. If you try to write a recursive function without the rec keyword, you’ll get a compile time error of “functionnamehere is not defined”.
What do you think about F# type providers? Are they useful? Haskell, SML or OCaml have something similar?
Amusingly OCaml, a language from which F# drew inspiration heavily has a decent proposal termed modular-implicits of adding them to the language.
(As a scala programmer:)
Implicit parameters are mainly used for implementing typeclasses. It would be great to have a comparison between Scala implicits, Haskell typeclasses, and F# “computation expressions” (and maybe throw in the OCaml “modular implicits” feature proposal).
Underscores are great.
Tail-recursion in Scala is unfortunately very limited (since it’s just done by the compiler rewriting the function). I don’t know what F# has in that regard.
Call by name is a pretty minor feature IME. It makes it easier to add custom control-flow-like syntax. IMO it’s probably not worth the overhead of dedicated syntax.
It’s worth saying that
trait
s are a limited form of multiple inheritance that avoids the biggest problem by forcing each class to inherit from exactly one class with a constructor.Nothing
is minor and useful.While it’s true that there’s nothing at the language level to force good code structure practice, multi-module projects with maven or the like are a very common practice (even quite small libraries are often split into several modules).
That last one is very different; F# computation expressions are “just” monads, repackaged in more mainstream vocabulary and with a slightly more explicit syntax. I think Microsoft was brilliant for giving them a different name (though I still honestly wish they’d just kept them called “workflows”, which was even less scary.)
The CLR can do full tail recursion; F# as a language requires recursive functions be tagged as such for namespace reasons (exactly like OCaml), but the CLR itself can do full-blown TCO out-of-the-box.
I don’t think the author was really complaining about traits, as much as complaining about Scala’s use of them in the stdlib. F# does lack them, but they’ve always seemed less necessary to me there, perhaps due to runtime generics letting me use normal polymorphism to get similar benefits.
Actually F# computation expressions are not “just” monads. http://tomasp.net/academic/papers/computation-zoo/computation-zoo.pdf
that is a pretty cool pdf :O
Computation expressions are better described as syntactic sugar for monads, so that nested binds and returns can be shown more intuitively (and compactly).
let maybe = new MaybeBuilder() let sugared = maybe { let x = 12 let! y = Some 11 let! z = Some 30 return x + y + z }
…. is equivalent to
let maybe = new MaybeBuilder(); let desugared = maybe.Delay(fun () -> let x = 12 maybe.Bind(Some 11, fun y -> maybe.Bind(Some 30, fun z -> maybe.Return(x + y + z) ) ) )
source: https://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions