I have a type with a constructor taking two arguments:
type Foo = Foo of int * int
And I can call it with a tuple of (int, int).
let foo = Foo(1,2)
But in my case I want to partially apply the constructor to use it in a pipe
let someFunc param =
calculateSomeInt param
|> Foo 42 //error
But this is not possible because the constructor cannot be called in curried form.
Is there some possibility to tell F# I want the constructor in curried form without having to define a new function let fooCtr a b = Foo (a,b)?
No, there isn't. The let fooCtr a b = Foo (a,b) approach you mentioned in your question is the only way to do this. (I would probably call it makeFoo or better yet mkFoo rather than fooCtr myself, since I feel that function names should be verbs, but that's personal style preference).
rmunn's answer is correct, but I'd like to add a detail.
You can add the constructor as a parameter to the make function, so you can use make to partially apply any constructor which takes a pair (a 2-tuple) as parameter:
type TypeA =
| A of int*int
| B of int*string
type TypeB =
| C of int*float
// make : (('a * 'b -> 'c) -> 'a -> 'b -> 'c)
let make t a b = t(a,b)
// x : int -> TypeA
let x = make A 1
// y : string -> TypeA
let y = make B 2
// z : float -> TypeB
let z = make C 3
In fact, it works with any function which takes a pair as parameter, so the name make is slightly misleading in this case.
Related
F# does not (currently) support type-classes. However, F# does support the OOP aspects of C#.
I was wondering, what is lost doing this approach compared to true type-classes?
// A concrete type
type Foo =
{
Foo : int
}
// "Trait" for things that can be shown
type IShowable =
abstract member Show : unit -> string
module Showable =
let show (showable : IShowable) =
showable.Show()
// "Witness" of IShowable for Foo
module Foo =
let asShowable (foo : Foo) =
{
new IShowable with
member this.Show() = string foo.Foo
}
// Slightly awkward usage
{ Foo = 123 }
|> Foo.asShowable
|> Showable.show
|> printfn "%s"
Your suggestion works for simple typeclasses that operate on a single value of a type, like Show. However, what happens when you need a typeclass that isn't so object-oriented? For example, when we want to add two numbers, neither one corresponds to OO's this object:
// not real F#
typeclass Numeric<'a> = // e.g. Numeric<int> or Numeric<float>
abstract member (+) : 'a -> 'a -> 'a // e.g. 2 + 3 = 5 or 2.0 + 3.0 = 5.0
...
Also, keep in mind that many useful typeclasses require higher-kinded types. For example, consider the monad typeclass, which would look something like this:
// not real F#
typeclass Monad<'m<_>> = // e.g. Monad<Option<_>> or Monad<Async<_>>
abstract member Return<'a> : 'a -> 'm<'a>
abstract member Bind<'a, 'b> : 'm<'a> -> ('a -> 'm<'b>) -> 'm<'b>
There's no good way to do this with .NET interfaces.
Higher-kinded type classes are indeed impossible to model with interfaces, but that's just because F# does not support higher-kindedness, not because of type classes themselves.
The deeper thing to note is that your encoding isn't actually correct. Sure, if you just need to call show directly, you can do asShowable like that, but that's just the simplest case. Imagine you needed to pass the value to another function that wanted to show it later? And then imagine it was a list of values, not a single one:
let needsToShow (showable: IShowable) (xs: 'a list) =
xs |> List.iter (fun x -> ??? how do I show `x` ???)
No, this wouldn't do of course. The key is that Show should be a function 'a -> string, not unit -> string. And this means that IShowable itself should be generic:
// Haskell: class Showable a where show :: a -> String
type IShowable<'a> with
abstract member Show : 'a -> string
// Haskell: instance Showable Foo where show (Foo i) = show i
module Foo =
let showable = { new IShowable<Foo> with member _.Show foo = string foo.Foo }
// Haskell: needsToShow :: Show a => [a] -> IO ()
let needsToShow (showable: IShowable<'a>) (xs: 'a list) =
xs |> List.iter (fun x -> printfn "%s" (showable.Show x))
// Haskell: needsToShow [Foo 1, Foo 42]
needsToShow Foo.showable [ { Foo: 1 }; { Foo: 42 } ]
And this is, essentially, what type classes are: they're indeed merely dictionaries of functions that are passed everywhere as extra parameters. Every type has such dictionary either available right away (like Foo above) or constructable from other such dictionaries, e.g.:
type Bar<'a> = Bar of 'a
// Haskell: instance Show a => Show (Bar a) where show (Bar a) = "Bar: " <> show a
module Bar =
let showable (showA: IShowable<'a>) =
{ new IShowable<Bar<'a>> with member _.Show (Bar a) = "Bar: " + showA.Show a }
This is completely equivalent to type classes. And in fact, this is exactly how they're implemented in languages like Haskell or PureScript in the first place: like dictionaries of functions being passed as extra parameters. It's not a coincidence that constraints on function type signatures even kinda look like parameters - just with a fat arrow instead of a thin one.
The only real difference is that in F# you have to do that yourself, while in Haskell the compiler figures out all the instances and passes them for you.
And this difference turns out to be kind of important in practice. I mean, sure, for such a simple example as Show for the immediate parameter, you can just pass the damn instance yourself. And even if it's more complicated, I guess you could suck it up and pass a dozen extra parameters.
But where this gets really inconvenient is operators. Operators are functions too, but with operators there is nowhere to stick an extra parameter (or dozen). Check this out:
x = getY >>= \y -> getZ y <&> \z -> y + 42 > z
Here I used four operators from four different classes:
>>= comes from Monad
<&> from Functor
+ from Num
> from Ord
An equivalent in F# with passing instances manually might look something like:
let x =
bind Foo.monad getY <| fun y ->
map Bar.functor (getZ y) <| fun z ->
gt Int.ord (add Int.num y 42) z
Having to do that everywhere is quite unreasonable, you have to agree.
And this is why many F# operators either use SRTPs (e.g. +) or rely on "known" interfaces (e.g. <) - all so you don't have to pass instances manually.
I have a made a simple function that wraps common F# functions of signature 'a -> 'b -> 'c option to more "C# compliant" function as : 'a -> b -> byref<'c> -> bool. But somehow when I try to wrap such a method in a class I am getting error FS0001 and I can't locate the error.
Code below
open System
open System.Runtime.InteropServices
// Given a function, f: 'a -> 'b -> 'c option returns
// A new function g: 'a -> 'b -> byref<'c> -> bool
let wrapOptionF f a b (g:byref<'c>) =
match f a b with
| Some v ->
do g <- v
true
| None ->
false
let tryDivide (a:int) (b:int) =
match Math.DivRem(a,b) with
| v, 0 -> Some v
| _ -> None
type TryDivideWrapper() =
static member TryDivide(a, b, [<Out>]cRef:byref<int>) : bool =
let f = wrapOptionF tryDivide a b
f cRef
The offending line is f cRef.
This post contains a more in-depth explanation, but in short you can replace your final type definition with the following:
type TryDivideWrapper() =
static member TryDivide(a, b, [<Out>]cRef:byref<int>) : bool =
wrapOptionF tryDivide a b &cRef
The reason for this is that your wrapOptionF takes a byref parameter. However, byref<int> isn't really a type like int or int ref - it's just an indication to the compiler that your parameter should be passed by reference (like out in C#). Once inside your function, however, what you have is a regular int.
Edit: Note that Intellisense will show cRef as having type byRef<int>. However, if you bind another variable to cRef, you'll see that the type you get is a regular int. You can put this line inside TryDivide and then hover your mouse over a to see it:
let a = cRef
Using the & operator tells the compiler that you're passing cRef into f by reference - which is exactly what f needs - making the type system happy. I've tested this using a C# project, and TryDivideWrapper.TryDivide(a, b, out c) works as expected. Add in #MarkSeemann's tryDivide and you should be good to go.
I'm not exactly sure I understand the reason, but this seems to work:
type TryDivideWrapper() =
static member TryDivide(a, b, [<Out>]cRef:byref<int>) : bool =
wrapOptionF tryDivide a b &cRef
BTW, the OP tryDivide implementation throws an exception on tryDivide 1 0. Here's an alternative implementation that works:
let tryDivide (a:int) (b:int) =
if b = 0
then None
else Some (a / b)
FSI:
> tryDivide 1 0;;
val it : int option = None
> tryDivide 10 5;;
val it : int option = Some 2
I have a need to use statically resolved type parameters in a situation similar to the below:
[<Struct>]
type Wrapper<'T> =
val raw:'T
new(v:'T) = {raw = v}
type Value =
| Float of float
| Int of int
| String of string
with
member this.ToWrapper() :'T =
match this with
| Float f -> Wrapper<float>(f) // type is inferred as float
| Int i -> Wrapper<int>(i) // error
| String s -> Wrapper<string>(s) // error
How do I define and use a ToWrapper function (or set thereof) that can map a 'Value' type to any type within the Generic Wrapper<'T> where I know 'T will be either float | int | string?
The Wrapper<'T> type needs to be a Struct so interfaces aren't an option - as suggested in some other posts related to this.
It's not clear to me what are you trying to achieve. Are you trying to restrict the wrapped types to Int, String and Float?
1) If so you can check at runtime like this:
[<Struct>]
type Wrapper<'T> =
val raw:'T
new(v:'T) = {raw = v}
let wrap x =
match box x with
| :? float -> ()
| :? int -> ()
| :? string -> ()
| _ -> failwith "invalid type"
Wrapper x
let a = wrap 90
let b = wrap "hi"
let c = wrap true // fails at runtime
2) If you want to restrict at compile-time an easy way is to add static members as constructors:
[<Struct>]
type Wrapper<'T> =
val raw:'T
private new(v:'T) = {raw = v}
with
static member wrap (x:float) = Wrapper x
static member wrap (x:int) = Wrapper x
static member wrap (x:string) = Wrapper x
let a = Wrapper<_>.wrap 90
let b = Wrapper<_>.wrap "hi"
let c = Wrapper<_>.wrap true // doesn't compile
3) Or may be, using the DU inside the wrapper makes more sense for you:
type Value =
| Float of float
| Int of int
| String of string
[<Struct>]
type Wrapper =
val raw:Value
new(v:Value) = {raw = v}
Of all solutions 3) is the only one that really restricts your wrapper. Solutions 1) and 2) restrict the way you construct it.
From 2) you can use some tricks with statically resolved type parameters in order to come up with an inline function (not a method) that will wrap only on those types. Still that will not constraint the type itself, but since the constructor is private the code that consumes your type will be forced through your restricted constructors.
Statically resolved type parameters work with functions or methods but not on types, since they are a compile time F# feature, not a .NET type system feature.
You can't do this, because Wrapper<float> isn't the same type as Wrapper<int> (which also isn't the same type as Wrapper<string>). What would the return type of ToWrapper be? It can't be all three at once.
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")
What I am trying to write:
type A() =
interface IX with ...
interface IY with ...
type B() =
interface IX with ...
interface IY with ...
let mk t : 'T when 'T :> IX and 'T :> IY =
match t with
| Choice1 -> new A()
| Choice2 -> new B()
Note the type constraints on the return type of mk. It does not compile though, the compiler complains that it can't convert A and B to 'T.
The constraint is okay, but the problem is that there is no type that would satisfy the constraint and that would be a supertype of both A and B.
The match construct needs to return the same type from both of the branches, so you'd need to add upcast (:>) to some type such that the conversion works for both of the branches. The type could be either IX or IY, but that wouldn't satisfy the constraint.
This would be possible only if .NET allowed you to write something like IX+IY which would mean a type that implements both of the interfaces. Then you would also be able to work with values of this type e.g.:
let (a:IX+IY) = new A() // This isn't supported
I think that the best solution is to simply return a tuple IX * IY containing two times the same instance, but represented as different type. Here the constriant you wrote can be quite useful:
// Type: 'a -> IX * IY when 'a :> IX and 'a :> IY
let asTuple a = (a :> IX, a :> IY)
let mk t =
match t with
| Choice1Of2() -> new A() |> asTuple
| Choice2Of2() -> new B() |> asTuple
If you control types A and B, then the simplest solution would be to define
type IXY =
inherit IX
inherit IY
and then have A and B inherit IXY, and mk would just return an IXY rather than a generic type (which doesn't really make sense anyway, even without the constraints).