First off, I have a better method of dealing with this issue so it's not a problem.
However, it is something that I don't understand. Can someone explain this?
When I define the swap function as:
namespace Utilities
module Misc
let Swap (left : 'a byref) (right : 'a byref) =
let temp = left
left <- right
right <- temp
I am able to use the Swap function like this just fine.
Misc.Swap (&s.[i]) (&s.[j])
But when I define the module like:
namespace Utilities
type Misc =
static member Swap (left : 'a byref) (right : 'a byref) =
let temp = left
left <- right
right <- temp
I get the following error on both arguments:
This expression has type 'b byref but is here used with type 'a ref
How did the type inference for the caller's arguments change by moving the function into a type?
This may be an interaction with the tuple transformation that the F# compiler performs on class methods.
Reflector reports the type of Misc.Swap as:
public static void Swap<a>(ref a left, ref a right);
so we can see here that the compiler has transformed the curried arguments into tupled form.
Defining the method with tupled arguments avoids this problem:
type Misc =
static member Swap(left : 'a byref, right : 'a byref) =
let temp = left
left <- right
right <- temp
> let s = Array.init 3 (fun i -> i)
> val s : int array = [|0; 1; 2|]
> Misc.Swap (&s.[2], &s.[0])
> s;;
> val s : int array = [|2; 1; 0|]
Related
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.
I'm doing a fun project in F#, which is a DSL for Camel.Net.
At some point, I want to check conditions. But the conditions entered by the programmer should evaluate to an object tree. So I want the experssion "a = b" evaluate to "SomeType.Equals(a,b)"
Is that even possible in F#?
I have this:
type Macro =
| Header of string
| XPath of string
| Const of string
| Func of (Message -> string)
with
static member (=) (l:Macro, r:Macro) = Equals(l,r)
static member (=) (l:Macro, r:string) = Equals(l,Const(r))
and Comparison =
| Equals of Macro * Macro
Now everything in "Macro" will work as "Macro.Func" - with "Func"; a function is executed with "Message" as input param and will output the string. So the Equals(a,b) will evaluate to a string comparison during runtime.
But this code has a problem. Operator (=) does compile (it has a warning), but it can't be used as I would like.
This does not compile in the fsi:
let c1 = Header("property") = "somevalue"
I did read another question about this topic, and a bit more.
It does not answer my question.
[<NoEquality; NoComparison>] - completely shuts off the (=) operator.
[<CustomEquality; CustomComparison>] - wants you to implement an (=) operator which returns bool.
Is it even possible in F# what I want? And assuming that I can find a way, does match x with still work?
Sure, I did this reimplement to the operator in terms of System.IEquatable<T> for performance reasons:
#nowarn "86" // F# doesn't like it when you do this
[<AutoOpen>]
module FastEquals =
let inline eq<'a when 'a :> System.IEquatable<'a>> (x:'a) (y:'a) = x.Equals y
let inline (=) x y = eq x y
let inline (<>) x y = not (eq x y)
Just an example, you'll need to adapt for your own purposes.
Thanks to Asik's answer above, in combination with a reread of this post:
This works in the fsi:
type Message = class end
type Macro =
| Header of string
| XPath of string
| Const of string
| Func of (Message -> string)
type Comparison =
| Equals of Macro * Macro
type Operators = Operation with
static member CompareEquals (Operation, l:Macro, r:Macro) = Equals(l,r)
static member CompareEquals (Operation, l:Macro, r:string) = Equals(l,Const(r))
#nowarn "0086" "0064"
let inline (=) (l:'N) (r:'M) = ((^T or ^N or ^M) : (static member CompareEquals : ^T * ^N * ^M -> _) (Operation, l, r))
let c1 = Header("property1") = Header("property2")
let c2 = Header("property") = "somevalue"
Note that it does not work when the static "CompareEquals" methods are located in the "Macro" type.
If you look at the signature of op_Equals:
val inline ( = ) :
l: ^N -> r: ^M -> 'a
when (Operators or ^N or ^M) : (static member CompareEquals : Operators * ^N * ^M -> 'a)
That is a really weird syntax. I don't understand the part after "when". It works, that counts.
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
What's the most idiomatic way in F# to deal with the following. Suppose I have a property I want a type to satisfy that doesn't make sense on an instance level, but ideally I would like to have some pattern matching available against it?
To make this more concrete, I have defined an interface representing the concept of a ring (in the abstract algebra sense). Would I go for:
1.
// Misses a few required operations for now
type IRing1<'a when 'a: equality> =
abstract member Zero: 'a with get
abstract member Addition: ('a*'a -> 'a) with get
and let's assume I'm using it like this:
type Integer =
| Int of System.Numerics.BigInteger
static member Zero with get() = Int 0I
static member (+) (Int a, Int b) = Int (a+b)
static member AsRing
with get() =
{ new IRing1<_> with
member __.Zero = Integer.Zero
member __.Addition = Integer.(+) }
which allows me to write things like:
let ring = Integer.AsRing
which then lets me to nicely use the unit tests I've written for verifying the properties of a ring. However, I can't pattern match on this.
2.
type IRing2<'a when 'a: equality> =
abstract member Zero: 'a with get
abstract member Addition: ('a*'a -> 'a) with get
type Integer =
| Int of System.Numerics.BigInteger
static member Zero with get() = Int 0I
static member (+) (Int a, Int b) = Int (a+b)
interface IRing2<Integer> with
member __.Zero = Integer.Zero
member __.Addition with get() = Integer.(+)
which now I can pattern match, but it also means that I can write nonsense such as
let ring = (Int 3) :> IRing2<_>
3.
I could use an additional level of indirection and basically define
type IConvertibleToRing<'a when 'a: equality>
abstract member UnderlyingTypeAsRing : IRing3<'a> with get
and then basically construct the IRing3<_> in the same way as under #1.
This would let me write:
let ring = ((Int 3) :> IConvertibleToRing).UnderlyingTypeAsRing
which is verbose but at least what I'm writing doesn't read as nonsense anymore. However, next to the verbosity, the additional level of complexity gained doesn't really "feel" justifiable here.
4.
I haven't fully thought this one through yet, but I could just have an Integer type without implementing any interfaces and then a module named Integer, having let bound values for the Ring interfaces. I suppose I could then use reflection in a helper function that creates any IRing implementation for any type where there is also a module with the same name (but with a module suffix in it's compiled name) available? This would combine the benefits of #1 and #2 I guess, but I'm not sure whether it's possible and/or too contrived?
Just for background: Just for the heck of it, I'm trying to implement my own mini Computer Algebra System (like e.g. Mathematica or Maple) in F# and I figured that I would come across enough algebraic structures to start introducing interfaces such as IRing for unit testing as well as (potentially) later for dealing with general operations on such algebraic structures.
I realize part of what is or isn't possible here has more to do with restrictions on how things can be done in .NET rather than F#. If my intention is clear enough, I'd be curious to here in comments how other functional languages work around this kind of design questions.
Regarding your question about how can you implement Rings in other functional languages, in Haskell you will typically define a Type Class Ring with all Ring operations.
In F# there are no Type Classes, however you can get closer using inline and overloading:
module Ring =
type Zero = Zero with
static member ($) (Zero, a:int) = 0
static member ($) (Zero, a:bigint) = 0I
// more overloads
type Add = Add with
static member ($) (Add, a:int ) = fun (b:int ) -> a + b
static member ($) (Add, a:bigint) = fun (b:bigint) -> a + b
// more overloads
type Multiply = Multiply with
static member ($) (Multiply, a:int ) = fun (b:int ) -> a * b
static member ($) (Multiply, a:bigint) = fun (b:bigint) -> a * b
// more overloads
let inline zero() :'t = Zero $ Unchecked.defaultof<'t>
let inline (<+>) (a:'t) (b:'t) :'t= (Add $ a) b
let inline (<*>) (a:'t) (b:'t) :'t= (Multiply $ a) b
// Usage
open Ring
let z : int = zero()
let z': bigint = zero()
let s = 1 <+> 2
let s' = 1I <+> 2I
let m = 2 <*> 3
let m' = 2I <*> 3I
type MyCustomNumber = CN of int with
static member ($) (Ring.Zero, a:MyCustomNumber) = CN 0
static member ($) (Ring.Add, (CN a)) = fun (CN b) -> CN (a + b)
static member ($) (Ring.Multiply, (CN a)) = fun (CN b) -> CN (a * b)
let z'' : MyCustomNumber = zero()
let s'' = CN 1 <+> CN 2
If you want to scale up with this approach you can have a look at FsControl which already defines Monoid with Zero (Mempty) and Add (Mappend). You can submit a pull request for Ring.
Now to be practical if you are planning to use all this only with numbers why not use GenericNumbers in F#, (+) and (*) are already generic then you have LanguagePrimitives.GenericZero and LanguagePrimitives.GenericOne.
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")