I am still confused on how to read function signatures.
The Option.map signature is the following:
/// map f inp evaluates to match inp with None -> None | Some x -> Some (f x).
/// mapping: A function to apply to the option value.
/// option: The input option.
val map : mapping:('T -> 'U) -> option:'T option -> 'U option
However, I have no clue what that signature means.
I read it as the following:
There's a function called map that takes a function as an input that we'll call "mapping" and it will yield a result that is also a function that we'll call "option".
Mapping Parameter:
mapping:('T -> 'U)
The function that we pass in as input takes Titanium (i.e. 'T) as the input and yields Uranium (i.e. 'U) as output.
The Option returned
option:'T option -> 'U option
We'll call the output of the map function "option".
Thus, this "option" that is returned from executing the map function is also a function as referenced above. It's takes a Titanium option and yields a Uranium option.
Example:
type String20 = String20 of string
type Name = { First:String20
Last:String20
Suffix:String20 option }
let tryCreateName (first:string) (last:string) (suffix:string option) =
let isValid = [first; last]
|> List.forall (fun x -> x.Length > 2 && x.Length <= 20)
if isValid then
Some { First = String20(first);
Last = String20(last);
Suffix = Option.map String20 suffix }
else None
How does the following expression map:
Option.map String20 suffix
Based on the expression above, where is the "returned function" of Titanium option -> Uranium option?
First off take a look at Option.map<'T,'U> Function (F#) and notice
The expression map f inp evaluates to match inp with None -> None |
Some x -> Some (f x).
So lets convert this comment to working code. First map is a method of the type Option, but to make it easier we will make it a function outside of a type and to avoid conflicts with other map functions we will give it the name OptionMap.
let OptionMap = f inp =
match inp with
| None -> None
| Some x -> Some (f x)
Now to get the signature of this function just send it to F# Interactive
val OptionMap : f:('a -> 'b) -> inp:'a option -> 'b option
and to make the types obvious we will type the parameters of the function.
let optionMap (f : ('a -> 'b)) (inp : 'a option) : 'b option =
match inp with
| None -> None
| Some x -> Some (f x)
Now to test this we can use
let (test : String20 option) = optionMap String20 (Some("something"))
printfn "test: %A" test
// test: Some (String20 "something")
So what happened in OptionMap that allowed this to work
If we add some print statements let sees what happens
let optionMap (f : ('a -> 'b)) (inp : 'a option) : 'b option =
printfn "f: %A" f
printfn "inp: %A" inp
match inp with
| None -> None
| Some x ->
let result = Some (f x)
printfn "result: %A" result
result
we get
f: <fun:test#63>
inp: Some "something"
result: Some (String20 "something")
we see that f is a function which is String20
So how can String20 be a function?
If we send String20 to F# Interactive it gives.
> String20;;
val it : arg0:string -> String20 = <fun:clo#4>
So String20 is a function that takes a string and returns a type of String20. That smells of a constructor.
Let's test that out in F# interactive.
> let test1 = String20 "something";;
val test1 : String20 = String20 "something"
Sure enough, String20 is a constructor, but we didn't specifically create a constructor as is done in the Object-Oriented world.
You have to think of a type, even a discriminated union as having constructors. The constructors are not specifically written but do exist. So String20 is a constructor that takes one value, a string, which is a function with the correct type signature for the Option.map function.
I gave the answer a lot more detail so that one can learn a process on how to break down problems and look at the inner workings as a tool to solving these kinds of problems.
To learn more about the lower level details of how functional programming works one needs to understand lambda calculus. The best way I know to learn it is to read An Introduction To Functional Programming Through Lambda Calculus by Greg Michaelson and look at the info in the lambda calculus tag.
Also if you like the book, you should buy a copy instead of using the free version.
There are two ways of looking at it.
let f x y = x + y
// val f: x:int -> y:int -> int
One way is to say that function f takes two parameters, x of type int and y of type int, and returns an int. So I can supply two arguments and get the result:
let a = f 4 5
// val a: int = 9
The other way is that the function takes one parameter, x of type int, and returns another function, which takes one parameter, y of type int, and returns an int. So I can supply one argument and get a function as result:
let b = f 4
// val b: int -> int
Mathematically, it's always the second way - all functions are one-parameter functions. This notion is very convenient for programming with higher-order functions.
But the first way is usually more understandable to humans, so you will often see functions discussed as if they take multiple parameters.
String20 is the case constructor for the String20 Discriminated Union case. It's a function with the type string -> String20. So string takes the place of 'T, and String20 takes the place of 'U in the mapping you supply to Option.map.
Generally, if you have a function T1 -> T2 -> ... and you apply it to one parameter, you get a function T2 -> .... In the case of Option.map, T1 is itself a function, but that is of no consequence to the way the arguments are applied.
I find it confusing to call a function "option", a string "Titanium" and a type called String20 "Uranium", so I'll stick with type names.
You ask where the "returned function" that maps a string option to a String20 option is in the expression Option.map String20 suffix. It is simply
Option.map String20
Since String20 constructs a String20 from a string, Option.map String20 is a function that maps a string to a String20 if it is present, and to None otherwise.
If you write Option.map String20 suffix, this function is applied to suffix, which would be a string option. The result of this expression is a String20 option.
Related
I have a type that I'm trying to understand by writing unit tests against it, however I can't reason what to do with PrintfFormat
type ValueFormat<'p,'st,'rd,'rl,'t,'a> = {
format: PrintfFormat<'p,'st,'rd,'rl,'t>
paramNames: (string list) option
handler: 't -> 'a
}
with
static member inline construct (this: ValueFormat<_,_,_,_,_,_>) =
let parser s =
s |> tryKsscanf this.format this.handler
|> function Ok x -> Some x | _ -> None
let defaultNames =
this.format.GetFormatterNames()
|> List.map (String.replace ' ' '_' >> String.toUpperInvariant)
|> List.map (sprintf "%s_VALUE")
let names = (this.paramNames ?| defaultNames) |> List.map (sprintf "<%s>")
let formatTokens = this.format.PrettyTokenize names
(parser, formatTokens)
I feel confident that I can figure everything out but PrintfFormat is throwing me with all those generics.
The file I'm looking at for the code I want to unit test is here for the FSharp.Commandline framework.
My question is, what is PrintfFormat and how should it be used?
A link to the printf.fs file is here. It contains the definition of PrintfFormat
The PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple> type, as defined in the F# source code, has four type parameters:
'Result is the type that your formatting/parsing function produces. This is string for sprintf
'Printer is a type of a function generated based on the format string, e.g. "%d and %s" will give you a function type int -> string -> 'Result
'Tuple is a tuple type generated based on the format string, e.g. "%d and %s" will give you a tuple type int * string.
'State and 'Residue are type parameters that are used when you have a custom formatter using %a, but I'll ignore that for now for simplicity (it's never needed unless you have %a format string)
There are two ways of using the type. Either for formatting, in which case you'll want to write a function that returns 'Printer as the result. The hard thing about this is that you need to construct the return function using reflection. Here is an example that works only with one format string:
open Microsoft.FSharp.Reflection
let myformat (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Printer =
unbox <| FSharpValue.MakeFunction(typeof<'Printer>, fun o ->
box (o.ToString()) )
myformat "%d" 1
myformat "%s" "Yo"
This simply returns the parameter passed as a value for %d or %s. To make this work for multiple arguments, you'd need to construct the function recursively (so that it's not just e.g. int -> string but also int -> (int -> string))
In the other use, you define a function that returns 'Tuple and it needs to create a tuple containing values according to the specified formatting string. Here is a small sample that only handles %s and %d format strings:
open FSharp.Reflection
let myscan (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Tuple =
let args =
fmt.Value
|> Seq.pairwise
|> Seq.choose (function
| '%', 'd' -> Some(box 123)
| '%', 's' -> Some(box "yo")
| _ -> None)
unbox <| FSharpValue.MakeTuple(Seq.toArray args, typeof<'Tuple>)
myscan "%d %s %d"
I'm messing around in F# and tried to write a function that can take an int list or a string list. I have written a function that is logically generic, in that I can modify nothing but the type of the argument and it will run with both types of list. But I cannot generically define it to take both.
Here is my function, without type annotation:
let contains5 xs =
List.map int xs
|> List.contains 5
When I try to annotate the function to take a generic list, I receive a warning FS0064: the construct causes the code to be less generic than indicated by the type annotations. In theory I shouldn't need to annotate this to be generic, but I tried anyway.
I can compile this in two separate files, one with
let stringtest = contains5 ["1";"2";"3";"4"]
and another with
let inttest = contains5 [1;2;3;4;5]
In each of these files, compilation succeeds. Alternately, I can send the function definition and one of the tests to the interpreter, and type inference proceeds just fine. If I try to compile, or send to the interpreter, the function definition and both tests, I receive error FS0001: This expression was expected to have type string, but here has type int.
Am I misunderstanding how typing should work? I have a function whose code can handle a list of ints or a list of strings. I can successfully test it with either. But I can't use it in a program that handles both?
You are running into value restrictions on the automatic generalization of the type inference system as outlined here
Specifically,
Case 4: Adding type parameters.
The solution is to make your function generic rather than just making its parameters generic.
let inline contains5< ^T when ^T : (static member op_Explicit: ^T -> int) > (xs : ^T list) =
List.map int xs
|> List.contains 5
You have to make the function inline because you have to use a statically resolved type parameter, and you have to use a statically resolved type parameter in order to use member constraints to specify that the type must be convertible to an int. As outlined here
You can use inline to prevent the function from being fixed to a particular type.
In FSI, the interactive REPL:
> open System;;
> let inline contains5 xs = List.map int xs |> List.contains 5;;
val inline contains5 :
xs: ^a list -> bool when ^a : (static member op_Explicit : ^a -> int)
> [1;2;3] |> contains5;;
val it : bool = false
> ["1";"2";"5"] |> contains5;;
val it : bool = true
Note that the signature of contains5 has a generic element to it. There's more about inline functions here.
This is already answered correctly above, so I just wanted to chime in with why I think it's a good thing that F# appears to makes this difficult / forces us to lose type safety. Personally I don't see these as logically equivalent:
let inline contains5 xs = List.map int xs |> List.contains 5
let stringTest = ["5.00"; "five"; "5"; "-5"; "5,"]
let intTest = [1;2;3;4;5]
contains5 stringTest // OUTPUT: System.FormatException: Input string was not in a correct format.
contains5 intTest // OUTPUT: true
When inlined, the compiler would create two logically distinct versions of the function. When performed on the list<int> we get a boolean result. When performed on a list<string> we get a boolean result or an exception. I like that F# nudges me towards acknowledging this.
let maybeInt i =
match Int32.TryParse i with
| true,successfullyParsedInteger -> Some successfullyParsedInteger
| _ -> None
let contains5 xs =
match box xs with
| :? list<int> as ixs ->
ixs |> List.contains 5 |> Ok
| :? list<string> as sxs ->
let successList = sxs |> List.map maybeInt |> List.choose id
Ok (successList |> List.contains 5)
| _ ->
Error "Error - this function expects a list<int> or a list<string> but was passed something else."
let stringTest = ["5.00"; "five"; "5"; "-5"; "5,"]
let intTest = [1;2;3;4;5]
let result1 = contains5 stringTest // OUTPUT: Ok true
let result2 = contains5 intTest // OUTPUT: Ok true
Forces me to ask if some of the values in the string list cannot be parsed, should I drop out and fail, or should I just try and look for any match on any successful parse results?.
My approach above is horrible. I'd split the function that operates on the strings from the one that operates on the integers. I think your question was academic rather than a real use case though, so I hope I haven't gone off on too much of a tangent here!
Disclaimer: I'm a beginner, don't trust anything I say.
I have two example types, defined in this order:
type Quote = {QuoteNum: decimal option; ShipToID: decimal option}
type Sales = {SalesNum: decimal option; ShipToID: decimal option}
and I'm trying to write a function that can accept a both types:
let fx (y: Map<decimal option, _ list>) =
y
|> Map.map (fun key list -> list
|> List.map (fun x -> x.ShipToID))
When I try to pass a Map<decimal option, Quote list> to the function, I get an error:
Type mismatch. Expecting a
Map<decimal option,Sales list>
but given a
Map<decimal option,Quote list>
I would have thought that I'd be able to pass a map of both types to the function, but the compiler seems to be inferring that only a Map<decimal option, Sales list> is acceptable to the function. I suspect that the compiler "sees" the Sales type most recently and assumes that that's what the function needs. I thought I had made the function relatively generic by including the _ in the type annotation.
How can I make the function accept both types? Can I do this without redefining the types themselves?
Your suspicions are correct. F# needs to infer a single concrete type there, so will use the most recent matching type it finds.
You can make it work by defining an interface with ShipToID field and have both types implement it (not sure if that counts as redefining the types for you), or by providing a getter function for extracting the field value (which would let you keep the function generic):
let fx (shipToIdGetter: 'a -> decimal option) (y: Map<decimal option, 'a list>) =
y
|> Map.map (fun key list ->
list
|> List.map (fun x -> shipToIdGetter x))
Your code would work as written if F# supported row polymorphism (which happens to be the case for OCaml).
While I believe that scrwtp's answer is the way to go, you also have the choice to use inline and member constraints (or static duck typing...if thats a valid term). For the sake of completeness:
type Quote = {QuoteNum: decimal option; ShipToID: decimal option}
type Sales = {SalesNum: decimal option; ShipToID: decimal option}
let inline fx (y: Map<decimal option, 'a list>) =
let inline getId x = ( ^a : (member ShipToID : decimal option) x)
y |> Map.map (fun key list -> list |> List.map getId)
let q : Quote = { QuoteNum = None; ShipToID = None}
let s : Sales = { SalesNum = None; ShipToID = None}
fx <| Map.ofList [ None, [q]]
fx <| Map.ofList [ None, [s]]
The getId function uses the rather obscure syntax to call the ShipToID member based on ^a's expected structure.
I'm quite sure that I run into some kind of limitation, but I do not understand it:
type IRunner =
abstract member Run : (string -> 'a) -> 'a
type T() =
let run4 doFun = doFun "4"
let run5 doFun = doFun "5"
let parseInt s = System.Int32.Parse(s)
let parseFloat s = System.Double.Parse(s)
let doSomething () =
let i = parseInt |> run4
let f = parseFloat |> run4
f |> ignore
// Make it more generic ->
//let doSomething2 (runner:(string->'a)->'b) =
let doSomething2 runner =
// Error on the following lines with both declarations
let i = parseInt |> runner
let f = parseFloat |> runner
f |> ignore
// Want to do something like
let test () =
doSomething2 run4
doSomething2 run5
// Workaround
let workaround (runner:IRunner) =
let run f = runner.Run f
let i = parseInt |> run
let f = parseFloat |> run
f |> ignore
Can somebody bring some light over this? I did not find any related question, sorry if i duplicated something.
The problem is, if doSomething2 has type ((string->'a) -> 'b) -> unit, then 'a and 'b are fixed during each invocation of doSomething2, which isn't what you want - in your case 'a needs to treated as both int and float during a single invocation of doSomething2.
It seems like what you really want is more like: doSomething2 : (forall 'a. (string -> 'a) -> 'a) -> unit, but that kind of direct universal quantification doesn't exist in F#. As you've discovered, the way to work around this is to use a type with a generic method.
And even if F# did support forall types, as I mentioned in a comment inference still wouldn't be possible. Consider your doSomething2 function - we know that runner needs to be able to take an input of type string -> int to some output type and an input of type string -> float to some (possibly different) output type. Here are several different signatures for doSomething2 that all meet this requirement:
forall 'a. 'a -> 'a
forall 'a. (string -> 'a) -> 'a
forall 'a. 'a -> unit
Note that none of these types is more general than the others, they are all incompatible. In the first case, we could pass id to the function, in the second case, we could pass run4 to it, and in the third case, we could pass ignore to it (but none of those functions is compatible with the other possible signatures!).
I have a function that takes a parameter of type object and needs to downcast it to an option<obj>.
member s.Bind(x : obj, rest) =
let x = x :?> Option<obj>
If I pass (for example) an Option<string> as x, the last line throws the exception: Unable to cast object of type 'Microsoft.FSharp.Core.FSharpOption'1[System.String]' to type 'Microsoft.FSharp.Core.FSharpOption'1[System.Object]'.
Or, if I try a type test:
member s.Bind(x : obj, rest) =
match x with
| :? option<obj> as x1 -> ... // Do stuff with x1
| _ -> failwith "Invalid type"
then x never matches option<obj>.
In order to make this work, I currently have to specify the type the option contains (e.g. if the function is passed an option<string>, and I downcast the parameter to that rather than option<obj>, the function works.
Is there a way I can downcast the parameter to option<obj> without specifying what type the option contains? I've tried option<_>, option<#obj>, and option<'a> with the same results.
By way of background, the parameter needs to be of type obj because I'm writing an interface for a monad, so Bind needs to bind values of different types depending on the monad that implements the interface. This particular monad is a continuation monad, so it just wants to make sure the parameter is Some(x) and not None, then pass x on to rest. (The reason I need the interface is because I'm writing a monad transformer and I need a way to tell it that its parameter monads implement bind and return.)
Update: I managed to get around this by upcasting the contents of the option before it becomes a parameter to this function, but I'm still curious to know if I can type-test or cast an object (or generic parameter) to an option without worrying about what type the option contains (assuming of course the cast is valid, i.e. the object really is an option).
There isn't any nice way to solve this problem currently.
The issue is that you'd need to introduce a new generic type parameter in the pattern matching (when matching against option<'a>), but F# only allows you to define generic type parameters in function declarations. So, your only solution is to use some Reflection tricks. For example, you can define an active pattern that hides this:
let (|SomeObj|_|) =
let ty = typedefof<option<_>>
fun (a:obj) ->
let aty = a.GetType()
let v = aty.GetProperty("Value")
if aty.IsGenericType && aty.GetGenericTypeDefinition() = ty then
if a = null then None
else Some(v.GetValue(a, [| |]))
else None
This will give you None or Some containing obj for any option type:
let bind (x : obj) rest =
match x with
| SomeObj(x1) -> rest x1
| _ -> failwith "Invalid type"
bind(Some 1) (fun n -> 10 * (n :?> int))
I am not certain why you need to get your input as obj, but if your input is an Option<_>, then it is easy:
member t.Bind (x : 'a option, rest : obj option -> 'b) =
let x = // val x : obj option
x
|> Option.bind (box >> Some)
rest x
To answer your last question: you can use a slight variation of Tomas' code if you need a general-purpose way to check for options without boxing values beforehand:
let (|Option|_|) value =
if obj.ReferenceEquals(value, null) then None
else
let typ = value.GetType()
if typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<option<_>> then
let opt : option<_> = (box >> unbox) value
Some opt.Value
else None
//val ( |Option|_| ) : 'a -> 'b option
let getValue = function
| Option x -> x
| _ -> failwith "Not an option"
let a1 : int = getValue (Some 42)
let a2 : string = getValue (Some "foo")
let a3 : string = getValue (Some 42) //InvalidCastException
let a4 : int = getValue 42 //Failure("Not an option")