Is it possible to forward an optional argument in F# - f#

I want to define an overloaded member function in F#
member o.m1(?x: int) =
o.m1("bugs bunny", x) // <- error, expects a straight int, but x is int option
member o.m1(s: string, ?x: int) =
42
but the code above fails. I can solve this so:
member o.m1(?x: int) =
match x with
| Some x -> o.m1("bugs bunny", x)
| _ -> o.m1("bugs bunny")
I wonder if it is possible to avoid this switch.

You can do it by explicitly naming the optional parameter, like this:
member o.m1(?x: int) =
o.m1("bugs bunny", ?x = x)

Related

How to constrain the return type of a function with an arbitrary amount of arguments?

I would like to create a record type with a type annotation, with the constraint that the annotation must be a function that returns a certain type. Consider this example below:
type Foo<'Function> = {
Function: 'Function
}
I would 'Function to be able to be any function, as long as it returns for example int, so that
{Function = (fun a b c d e f g -> 2)}
{Function = (fun a -> 2)}
work, but
{Function = (fun a -> "")}
would be invalid.
As far as i understand F# functions, they are a nested structure of tuples, where the most inner second tuple field is the return type of the function, which is the reason why neither of these:
type Foo<('Input -> int)> = {
Function: ('Input -> int)
}
type ReturnsInt = FSharpFunc<'Input,int>
will work for any function with more than one argument, because the result type is encapsulated in the second annotation in either the signature or FSharpFunc<_,_>. Is there a way to realize this as a type annotation?
Edit
As Fyodor suggested in the comments below, this can be overcome by using only functions that have tupled arguments, leading to the function annotation being
FSharpFunc<argumentTuples,ReturnType>, e.g.:
type Foo<'ArgumentTuples> = {
Function: 'ArgumentTuples -> int
}
{Function = (fun (a,b,c,d,e,f,g) -> 2)} // works
{Function = (fun a -> 2)} // works
{Function = (fun a -> "")} // wont work
While this approach has its own problems and is not the specific answer to the original question, this workaround/workflow adaptation might be enough for me. I'll leave this question up (can't mark the comment as answer anyways)
Perhaps I'm missing something here, but why not simply define your type as:
type Foo<'InputType> = {
Function: ('InputType -> int)
}
Or more generic:
type Foo<'InputType, 'OutputType> = {
Function: ('InputType -> 'OutputType)
}
Edit: Ok, I see the problem.
So to use Fyodors solution, do something like this:
type Foo<'InputType> = {
Function: ('InputType -> int)
}
let add a b = a + b
let myFunction = {
Function = (fun (a,b) -> add a b)
}
Something along these lines might work for you, although you should be careful about not loosing the general picture. The branching may explode if there is a lot of complexity in your data model.
module FunctionTests
//define function types templates
type F1<'a> = 'a -> int
type F2<'a, 'b> = 'a -> 'b -> int
type F3<'a, 'b, 'c> = 'a -> 'b -> 'c -> int
type F4<'a, 'b, 'c, 'd> = 'a -> 'b -> 'c -> 'd -> int
//define actual functions
let f1 : F1<string> = fun x ->
printf "calling f1: %s\n" x
1
let f2 : F2<string, string> = fun x y ->
printf "calling f2: %s; %s\n" x y
2
let f3 : F3<string, string, int> = fun x y z ->
printf "calling f2: %s; %s; %d\n" x y z
3
let f4 : F4<string, string, int, int> = fun x y z v ->
printf "calling f2: %s; %s; %d; %d\n" x y z v
4
//define DU limiting to a subset of functions
type FunctionChooser =
| FF1 of F1<string>
| FF2 of F2<string, string>
| FF3 of F3<string, string, int>
| FF4 of F4<string, string, int, int>
//define a record with the DU
type FunctionRec = {Function : FunctionChooser}
//testing harness
let callFunction (functiondefs : FunctionRec) data otherdata intparam1 intparam2 =
match functiondefs.Function with
| FF1 fn -> fn data
| FF2 fn -> fn data otherdata
| FF3 fn -> fn data otherdata intparam1
| FF4 fn -> fn data otherdata intparam1 intparam2
//tests
let res1 = callFunction {Function=FF1 f1} "somedata" "otherdata" 13 14
let res2 = callFunction {Function=FF2 f2} "somedata" "otherdata" 13 14
let res3 = callFunction {Function=FF3 f3} "somedata" "otherdata" 13 14
let res4 = callFunction {Function=FF4 f4} "somedata" "otherdata" 13 14

Using statically resolved type parameters is it possible to call class method with curried arguments?

type Test() =
member t.A(a: int -> int) (b: int) = ()
let cl = Test()
let f a b =
(^a : (member A: (int -> int) -> int -> unit) cl, a, b)
The above says that it cannot find the member or object contructor A. Is it possible to get the above to work somehow?
No, there's no way to call it without changing its definition.
I'm not sure if it's in the spec but you can find that restriction in the source code where it filters out curried members.
Anyway if you want to use curried arguments you can use a lambda function and it will work:
type Test() =
member t.A(a: int -> int) = fun (b: int) -> ()
let cl = Test()
let f a b =
(^a : (member A: (int -> int) -> (int -> unit)) cl, a) b

Function composition argument error

I have the following code snippet:
let add n x = x + n
let times n x = x * n
let addTimes = add 5 >> times 5
addTimes 4
and this works without any problem. But when I change like this
let add n x = x + n
let times n x = x * n
let addTimes = add >> times
addTimes 4
I've got the compiling error
error FS0071: Type constraint mismatch when applying the default type '(int -> int)' for a type inference variable. Expecting a type supporting the operator '*' but given a function type. You may be missing an argument to a function. Consider adding further type constraints
Why?
The signature of (>>) is ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3. I.e., it composes two unary functions – you are attempting to supply two binary functions, which is valid in general (though arguably not useful, or at the least unclear), but not for your function types:
Given that (f >> g) x is equivalent to g(f(x)), what would the expected outcome be when f is binary? In your case, x (int) is partially-applied to add (int -> int -> int), and that partial application ((int -> int)) is passed to times (also int -> int -> int), which obviously expects an int as its first parameter rather than the function type (int -> int).

In F#, what is the meaning of parentheses around operator type? [duplicate]

I have three functions that ought to be equal:
let add1 x = x + 1
let add2 = (+) 1
let add3 = (fun x -> x + 1)
Why do the types of these methods differ?
add1 and add3 are int -> int, but add2 is (int -> int).
They all work as expected, I am just curious as to why FSI presents them differently?
This is typically an unimportant distinction, but if you're really curious, see the Arity Conformance for Values section of the F# spec.
My quick summary would be that (int -> int) is a superset of int -> int. Since add1 and add3 are syntactic functions, they are inferred to have the more specific type int -> int, while add2 is a function value and is therefore inferred to have the type (int -> int) (and cannot be treated as an int -> int).

How to read F# type signatures?

I'm struggling with the F# type signature notation. For example let's say you have a Fold function:
let rec Fold combine acc l =
...
that may have this type signature:
('a -> 'b -> 'a) -> 'a -> list<'b> -> 'a
which I would read as
a function that has three arguments:
a function that takes an 'a, a 'b and returns an a'
an 'a
a list of 'b
and returns an 'a.
But then it would make more sense for my cavemen brain to express it as
('a, 'b -> 'a), 'a, list<'b> -> 'a
I'm sure there is a semantic reason why parameters are separated with an arrow exactly the same way as the function return type, but somehow I'm missing it and didn't found a clear explanation in books/articles so far. Every time I see a type signature I have to stop quite a bit of time to understand it. I feel like I'm just missing that little piece of the puzzle that makes the "decryption" obvious.
Can someone please enlighten me?
I'm sure there is a semantic reason
why parameters are separated with an
arrow exactly the same way as the
function return type, but somehow I'm
missing it and didn't found a clear
explanation in books/articles so far.
You're reading of the first function is correct. For instant deciphering, type signatures are expressed like this:
val functionName = inputType1 -> inputType2 -> ... -> inputTypeN -> returnType
Generally, arrow notation indicates a function is curry-able.
// val add4 : int -> int -> int -> int -> int
let add4 a b c d = a + b + c + d;;
// val f : (int -> int)
let f = add4 1 2 3 // returns (int -> int) waiting for last argument
Because the function is curried, you can technically write it like this:
// val add4 : int -> int -> int -> int -> int
let add4 = (fun a -> (fun b -> (fun c -> (fun d -> a + b + c + d))));;
// val f : (int -> int)
let f = fun x -> add4 1 2 3 x
If you think about it, the add4 signature is equivalent to this:
val add4 : int -> (int -> (int -> (int -> int) ) )
I believe we use arrow notation because it resembles the structure of the function when we explicitly curry arguments as shown above.
The signatures are written in that way because of what is called Currying. A slightly more accurate way of describing your function is that it takes a (function that takes a 'a and returns a function from a 'b to a 'a) and returns a function that takes a 'a and returns a function from a list<'b> to a 'a. Because of this the type signature can be rewritten as
('a -> 'b -> 'a) -> ('a -> (list<'b> -> 'a))
You could write a similar function in F# which has a type like you're proposing (but in F# it would be written as ('a * 'b -> 'a) * 'a * list<'b> -> 'a. However, the advantage of the existing function is that it's easy to partially apply it by only supplying a prefix of the arguments. For instance:
let sum = List.fold (+) 0
Using your definition, you'd have to write
let sum l = List.fold((fun (x,y) -> x + y), 0, l)
The reason for that is in Functional programming every function actually has only one parameter.
So lets say you have a function called Sum as :
int -> int -> int
It takes 2 int and return one int. Now if you call this function by just passing one int you won't get any compiler error, rather the return value will be of type int -> int. So you see this arrow notation fits with this behavior. This behavior is known as Currying.
Check out : http://en.wikipedia.org/wiki/Currying

Resources