Why can't I use optional parameters in loose functions defined with "let"?
Why are they only allowed in member functions?
I suspect they are provided only for compatibility with .NET functions. They aren't something you encounter in functional languages. The problem with an optional parameter is you can't curry it. If a function f's second parameter is optional, what is
let g = f x
?
Is it a function taking one argument, or a value obtained by evaluating f on x plus the default second parameter?
It is allowed in OCaml. Therefore it should be possible to implement it in F#.
http://caml.inria.fr/pub/docs/manual-ocaml/lablexamples.html#sec43
I guess it has been omitted for simplicity in F#.
Related
Curried functions in F#. I get the bit where passing in a subset of parameters yields a function with presets. I just wondered if passing all of the parameters is any different. For example:
let addTwo x y = x + y
let incr a = addTwo 1
let added = addTwo 2 2
incr is a function taking one argument.
Is added an int or a function? I can imagine an implementation where "added" is evaluated lazily only on use (like Schroedinger's Cat on opening the box). Is there any guarantee of when the addition is performed?
added is not a function; it is just a value that is calculated and bound to the name on the spot. A function always needs at least one parameter; if there is nothing useful to pass, that would be the unit value ():
let added () = addTwo 2 2
F# is an eagerly evaluated language, so an expression like addTwo 2 2 will immediately be evaluated to a value of the int type.
Haskell, by contrast, is lazily evaluated. An expression like addTwo 2 2 will not be evaluated until the value is needed. The type of the expression would still be a single integer, though. Even so, such an expression is, despite its laziness, not regarded as a function; in Haskell, such an unevaluated expression is called a thunk. That basically just means 'an arbitrarily complex expression that's not yet evaluated'.
incr is a function taking one argument. Is added an int or a function?
added, in this case, is a named binding that evaluates to an int. It is not a function.
I can imagine an implementation where "added" is evaluated lazily only on use (like Schroedinger's Cat on opening the box). Is there any guarantee of when the addition is performed?
The addition will be performed immediately when the binding is generated. There is no laziness involved.
As explained by TeaDrivenDev, you can change added to be a bound function instead of a bound value by adding a parameter, which can be unit:
let added () = addTwo 2 2
In this case, it will be a function, so the addition wouldn't happen until you call it:
let result = added () // Call the function, bind output to result
No. But kind of yes. But really, no.
You can construct a pure functional language that only has functions and nothing else. Lambda calculus is a complete algebra, so the theory is there. In this model, added can be considered a parameter-less function (in contrast to e.g. random(), where there's one parameter of type unit).
But F# is different. Since it's a rather pragmatic mix of imperative and functional programming, the result is not a function[1]. Instead, it's a value, just like a local in C#. This is no implementation detail - it's actually part of the F# specification. This does have disadvantages - it means its possible to have an ambiguous definition, where a definition could be either a value or a function definition (14.6.1).
[1] - Though in a pure functional program, you can't tell the difference - it's the same as just doing a substitution of the function with a cached value, which is perfectly legal.
What's the advantage of having a type represent a function?
For example, I have observed the following snippet:
type Soldier = Soldier of PieceProperties
type King = King of PieceProperties
type Crown = Soldier -> King
Is it just to support Partial Application when additional args have yet to be satisfied?
As Fyodor Soikin says in the comments
Same reason you give names to everything else - values, functions,
modules, etc.
In other words, think about programming in assembly which typically does not use types, (yes I am aware of typed assembly) and all of the problems that one can have and then how many of those problems are solved or reduced by adding types.
So before you programmed with a language that supported functions but that used static typing, you typed everything. Now that you are using F# which has static typing and functions, just extend what you have been using typing for but now add the ability to type the functions.
To quote Benjamin C. Pierce from "Types and Programming Languages"
A type system is a tractable syntactic method for proving the absence
of certain program behaviors by classifying phrases according to the
kinds of values they compute.
As noted in "Types and Programming Languages" Section 1.2
What Type Systems Are Good For
Detecting Errors
Abstraction
Documentation
Language Safety
Efficiency
TL;DR
One of the places that I find named type function definitions invaluable is when I am building parser combinators. During the construction of the functions I fully type the functions so that I know what the types are as opposed to what type inferencing will infer they are which might be different than what I want. Since the function types typically have several parameters it is easier to just give the function type a name, and then use that name everywhere it is needed. This also saves time because the function definition is consistent and avoid having to debug an improperly declared function definition; yes I have made mistakes by doing each function type by hand and learned my lesson. Once all of the functions work, I then remove the type definitions from the functions, but leave the type definition as comments so that it makes the code easier to understand.
A side benefit of using the named type definitions is that when creating test cases, the typing rules in the named function will ensure that the data used for the test is of the correct type. This also makes understanding the data for the test much easier to understand when you come back to it after many months.
Another advantage is that using function names makes the code easier to understand because when a person new to the code looks at if for the first time they can spot the consistency of the names. Also if the names are meaningful then it makes understanding the code much easier.
You have to remember that functions are also values in F#. And you can do pretty much the same stuff with them as other types. For example you can have a function that returns other functions. Or you can have a list that stores functions. In these cases it will help if you are explicit about the function signature. The function type definition will help you to constrain on the parameters and return types. Also, you might have a complicated type signature, a type definition will make it more readable. This maybe a bit contrived but you can do fun(ky) stuff like this:
type FuncX = int -> int
type FuncZ = float -> float -> float
let addxy (x:int) :FuncX = (+) x
let subxy :FuncX = (-) x
let addz (x:float) :FuncZ =
fun (x:float) -> (fun y -> x + y)
let listofFunc = [addxy 10;addxy 20; subxy 10]
If you check the type of listofFunc you will see it's FuncX list. Also the :FuncX refers to the return type of the function. But we could you use it as an input type as well:
let compFunc (x:FuncX) (z:FuncX) =
[(x 10);(z 10)]
compFunc (addxy 10) (addxy 20)
Most programming languages have some way of choosing an implementation at compile-time based on types. Function overloading is a common way of doing this. Using templates (in C++ or D possibly with constraits) is another option.
But in F#, I cannot find out how to do this without using class methods, and thus loosing some nice properties like currying.
let f (a:int) =
Gives Duplicate definition of 'f'
F# has statically resolved type parameters, but I don't how I can use this..
let f (a:^T) =
match T with
Gives The value or constructor of T is not defined at match T
let f (a:^T) =
match a with
| :> int as i ->
Gives Unexpected symbol ':>' in expression
let f (a:^T) =
match ^a with
| :> int as i ->
Gives Unexpected infix operator in expression
If you want to write a function that behaves differently for different types and is an ordinary F# function, then static member constraints let you do that. However, if you want to write idiomatic F# code, then there are other options:
Here is a good example showing how you can use static member constraints to do this
F# collections use different module for each type, so there is Array.map, List.map, Seq.map etc. This is idiomatic style for functional F# libraries.
FSharpChart is an example of a library that uses overloaded methods. Note that you can use static methods, so you can write Chart.Line [ ... ] and it will pick the right overload.
If you want to write generic numeric code, then I recently wrote a tutorial that covers this topic.
So, I would be a bit careful before using static constraints - it is not entirely idiomatic (e.g. not commonly used in standard libraries) and so it may cause some confusion. But it is quite powerful and certainly useful.
The key is that simply following patterns that work well in other languages might not give you the best results in F#. If you can provide a concrete example of what you're trying to do, then you might get a better results.
Why is it that functions in F# and OCaml (and possibly other languages) are not by default recursive?
In other words, why did the language designers decide it was a good idea to explicitly make you type rec in a declaration like:
let rec foo ... = ...
and not give the function recursive capability by default? Why the need for an explicit rec construct?
The French and British descendants of the original ML made different choices and their choices have been inherited through the decades to the modern variants. So this is just legacy but it does affect idioms in these languages.
Functions are not recursive by default in the French CAML family of languages (including OCaml). This choice makes it easy to supercede function (and variable) definitions using let in those languages because you can refer to the previous definition inside the body of a new definition. F# inherited this syntax from OCaml.
For example, superceding the function p when computing the Shannon entropy of a sequence in OCaml:
let shannon fold p =
let p x = p x *. log(p x) /. log 2.0 in
let p t x = t +. p x in
-. fold p 0.0
Note how the argument p to the higher-order shannon function is superceded by another p in the first line of the body and then another p in the second line of the body.
Conversely, the British SML branch of the ML family of languages took the other choice and SML's fun-bound functions are recursive by default. When most function definitions do not need access to previous bindings of their function name, this results in simpler code. However, superceded functions are made to use different names (f1, f2 etc.) which pollutes the scope and makes it possible to accidentally invoke the wrong "version" of a function. And there is now a discrepancy between implicitly-recursive fun-bound functions and non-recursive val-bound functions.
Haskell makes it possible to infer the dependencies between definitions by restricting them to be pure. This makes toy samples look simpler but comes at a grave cost elsewhere.
Note that the answers given by Ganesh and Eddie are red herrings. They explained why groups of functions cannot be placed inside a giant let rec ... and ... because it affects when type variables get generalized. This has nothing to do with rec being default in SML but not OCaml.
One crucial reason for the explicit use of rec is to do with Hindley-Milner type inference, which underlies all staticly typed functional programming languages (albeit changed and extended in various ways).
If you have a definition let f x = x, you'd expect it to have type 'a -> 'a and to be applicable on different 'a types at different points. But equally, if you write let g x = (x + 1) + ..., you'd expect x to be treated as an int in the rest of the body of g.
The way that Hindley-Milner inference deals with this distinction is through an explicit generalisation step. At certain points when processing your program, the type system stops and says "ok, the types of these definitions will be generalised at this point, so that when someone uses them, any free type variables in their type will be freshly instantiated, and thus won't interfere with any other uses of this definition."
It turns out that the sensible place to do this generalisation is after checking a mutually recursive set of functions. Any earlier, and you'll generalise too much, leading to situations where types could actually collide. Any later, and you'll generalise too little, making definitions that can't be used with multiple type instantiations.
So, given that the type checker needs to know about which sets of definitions are mutually recursive, what can it do? One possibility is to simply do a dependency analysis on all the definitions in a scope, and reorder them into the smallest possible groups. Haskell actually does this, but in languages like F# (and OCaml and SML) which have unrestricted side-effects, this is a bad idea because it might reorder the side-effects too. So instead it asks the user to explicitly mark which definitions are mutually recursive, and thus by extension where generalisation should occur.
There are two key reasons this is a good idea:
First, if you enable recursive definitions then you can't refer to a previous binding of a value of the same name. This is often a useful idiom when you are doing something like extending an existing module.
Second, recursive values, and especially sets of mutually recursive values, are much harder to reason about then are definitions that proceed in order, each new definition building on top of what has been already defined. It is nice when reading such code to have the guarantee that, except for definitions explicitly marked as recursive, new definitions can only refer to previous definitions.
Some guesses:
let is not only used to bind functions, but also other regular values. Most forms of values are not allowed to be recursive. Certain forms of recursive values are allowed (e.g. functions, lazy expressions, etc.), so it needs an explicit syntax to indicate this.
It might be easier to optimize non-recursive functions
The closure created when you create a recursive function needs to include an entry that points to the function itself (so the function can recursively call itself), which makes recursive closures more complicated than non-recursive closures. So it might be nice to be able to create simpler non-recursive closures when you don't need recursion
It allows you to define a function in terms of a previously-defined function or value of the same name; although I think this is bad practice
Extra safety? Makes sure that you are doing what you intended. e.g. If you don't intend it to be recursive but you accidentally used a name inside the function with the same name as the function itself, it will most likely complain (unless the name has been defined before)
The let construct is similar to the let construct in Lisp and Scheme; which are non-recursive. There is a separate letrec construct in Scheme for recursive let's
Given this:
let f x = ... and g y = ...;;
Compare:
let f a = f (g a)
With this:
let rec f a = f (g a)
The former redefines f to apply the previously defined f to the result of applying g to a. The latter redefines f to loop forever applying g to a, which is usually not what you want in ML variants.
That said, it's a language designer style thing. Just go with it.
A big part of it is that it gives the programmer more control over the complexity of their local scopes. The spectrum of let, let* and let rec offer an increasing level of both power and cost. let* and let rec are in essence nested versions of the simple let, so using either one is more expensive. This grading allows you to micromanage the optimization of your program as you can choose which level of let you need for the task at hand. If you don't need recursion or the ability to refer to previous bindings, then you can fall back on a simple let to save a bit of performance.
It's similar to the graded equality predicates in Scheme. (i.e. eq?, eqv? and equal?)
I've read through some of the post on here about closures and currying but I feel like I didn't find the answer. So what's the differences and possibly the similarities of closures and currying? Thanks for the help :)
Currying is really a mathematical concept first and foremost. It's the just observation that for any n-ary function f: S0×...Sn → R, you can define a new function fprime (just found a markdown bug!) with n-1 parameters where that first parameter is replaced by a constant. So, if you have a function add(a,b), you can define a new function add1(b) as
add1(b) ::= add(1, b)
...reading "::=" as "is defined to be."
A closure is more of a programming concept. (Of course, everything in programming is a mathematical concept as well, but closures became interesting because of programming.) When you construct a closure, you bind one or more variables; you're creating a chunk of code that has some variables tied to it.
The relationship is that you can use a closure in order to implement currying: you could build your add1 function above by making a closure in which that first parameter is bound to 1.