I am learning F# and I have the following code:
type Name = {first:string; last:string} // define a new type
let bob = {first="bob"; last="smith"} // define a value
// single parameter style
let f1 name = // pass in single parameter
let {first=f; last=l} = name // extract in body of function
printfn "first=%s; last=%s" f l
// match in the parameter itself
let f2 {first=f; last=l} = // direct pattern matching
printfn "first=%s; last=%s" f l
// test
f1 bob
f2 bob
My background is imperative programming and the value assignment works like this:
f = first
but the code above assigns value on the right side using
first=f
Why?
Here - F# is not assigning a variable, you are pattern matching.
The syntax here follows from how you would create a record as you are pattern matching to it - note the similarity between:
let f2 {first=f; last=l} =
and
let bob = {first="bob"; last="smith"}
and a more extreme example:
let f3 {first="bob"; last="smith"} =
Related
Wondering how to create a list of instantiated objects
I have this
type myType = GoodState | BadState
let create =
seq {for i in 1 .. 100000 do yield new myType}
this doesnt seem to work
anyone know a way of doing this?
thanks
myType is a Discriminated Union, so you have to choose one of the options.
type myType = GoodState | BadState
//using your syntax to create a sequence of BadState
let create1 = seq{for _ in 1 .. 100000 do BadState} //yield is not required anymore
//another syntax to create a list of GoodState
let create2 = List.init 100000 (fun _ -> GoodState)
By the way, I used an underline "_" because I'm not using the index in this example, but you could replace for a variable name if you inted to use it for something.
You construct values of myType using one of the two constructors you defined - GoodState and BadState. Neither have any arguments so you create values with:
let good : myType = GoodState
let bad : myType = BadState
You can construct a sequence of such values with e.g.
let create = seq {for i in 1 .. 100000 do yield GoodState}
See I have a single case discriminated union
type R = R of string * int * sting option * .....
And I got a value of R.
let r: R = getAValue ()
Now I need to replace the first item of r to an empty string and keep all other value. How to do it? Record type has the with construct
let r' = { r with Item1 = "" }
I know it can use 'pattern match' to extract all the items and create a new one. But it seems very cumbersome.
I assume you do not want to involve reflection, do you?
Then, I believe your only option would be using pattern matching. The (quite limited) burden would be defining the r-ity of your type Ras a pattern for matching.
Let's assume, for example, that your R wraps a tuple of 3 elements, i.e. has r-ity 3:
type R = R of string * int * string option
In this case all you need is to do define the following function:
let modR = function
| R(x,y,z) -> R("",y,z)
The signature of modR is R -> R, a quick check of your scenario:
let r = R("abc",1,None)
modR r
in fsi brings back
>
val it : R = R ("",1,None)
All you would need for applying the above to your specific R is set the actual r-ity of your type into the pattern.
UPDATE: As Fyodor Soikin pointed, a matching function isn't needed at all for unwrapping a single-case DU (see the docs). The sought convertion function definition may be defined as simple as
let modR (R(_,y,z)) = R("",y,z)
UPDATE2: While considering the comment from ca9163d9 I recalled just another flavor of pattern matching, namely as Pattern. Using it while implementing the sought conversion in the form of DU member gives:
type R = R of string * int * string option with
member self.modR() = let R(_,b,c) as x = self in R("",b,c)
Also #FyodorSoikin and #kaefer have pointed out in the comments that as x form isn't required for the simple DU unwrapping, similarly to terser modR function definition above:
member self.modR() = let (R(_,b,c)) = self in R("",b,c)
I'd like to create a type with a definition a bit like this:
type LeftRight<'left, 'right> = {
Left : 'left list
Right : 'right list
}
and a couple of functions:
let makeLeft xs = { Left = xs; Right = [] }
let makeRight ys = { Left = []; Right = ys }
and I'd like to provide a 'combiner' function:
let combine l r = { Left = l.Left # r.Left; Right = l.Right # r.Right }
When I try and make something, I (obviously!) get issues as my value is generic:
let aaa = makeLeft [1;2;3]
// Value restriction. The value 'aaa' has been inferred to have generic type
// val aaa : LeftRight<int,'_a>
If I combine a left and a right, type inference kicks in and everything's A-OK:
let bbb = makeRight [1.0;2.0;3.0]
let comb = combine aaa bbb // LeftRight<int, float>
but I want to use one with only lefts on its own. I tried creating an 'Any' type:
type Any = Any
and explicitly specified the types on makeLeft and makeRight:
let makeLeft xs : LeftRight<_, Any> = { Left = xs; Right = [] }
let makeRight ys : LeftRight<Any, _> = { Left = []; Right = ys }
which makes the value definitions happy, but makes the combine function sad:
let combined = combine aaa bbb
// Type mismatch. Expecting a
// LeftRight<int,Any>
// but given a
// LeftRight<Any,float>
// The type 'int' does not match the type 'Any'
I feel like there's probably a way around this with loads of voodoo with .Net's overloading of function calls, but I can't make it work. Has anyone tried this before/have any ideas?
The value restriction is not a problem in this case, you need the result of makeLeft or makeRight be generic if you ever hope to use them generically further down the line.
In F# (and OCaml), generic syntactic values must be explicitly marked as such, with full type annotations. Indeed, the compiler reports this:
error FS0030: Value restriction. The value 'aaa' has been inferred to
have generic type
val aaa : LeftRight Either define 'aaa' as a simple data term, make it a function with explicit arguments or, if you do
not intend for it to be generic, add a type annotation.
Without going into too much detail*, this is to avoid issues that can occur when combining polymorphism and side effects. The downside is that it does reject some perfectly safe code as a result.
So, the solution is simple, we make these values explicitly generic:
let aaa<'a> : LeftRight<int,'a> = makeLeft [1;2;3]
let bbb<'a> : LeftRight<'a, float> = makeRight [1.0;2.0;3.0]
Putting them together in FSI:
let comb = combine aaa bbb;;;
val comb : LeftRight<int,float> = {Left = [1; 2; 3];
Right = [1.0; 2.0; 3.0];}
Note that if you combine without intermediate let bindings, you no longer have a generic value and the proper type can be inferred by the compiler:
combine (makeLeft [1;2;3]) (makeRight [1.0;2.0;3.0]);;
val it : LeftRight<int,float> = {Left = [1; 2; 3];
Right = [1.0; 2.0; 3.0];}
*For more detail, check out this article.
Given an F# record:
type R = { X : string ; Y : string }
and two objects:
let a = { X = null ; Y = "##" }
let b = { X = "##" ; Y = null }
and a predicate on strings:
let (!?) : string -> bool = String.IsNullOrWhiteSpace
and a function:
let (-?>) : string -> string -> string = fun x y -> if !? x then y else x
is there a way to use F# quotations to define:
let (><) : R -> R -> R
with behaviour:
let c = a >< b // = { X = a.X -?> b.X ; Y = a.Y -?> b.Y }
in a way that somehow lets (><) work for any arbitrary F# record type, not just for R.
Short: Can quotations be used to generate F# code for a definition of (><) on the fly given an arbitrary record type and a complement function (-?>) applicable to its fields?
If quotations cannot be used, what can?
You could use F# quotations to construct a function for every specific record and then compile it using the quotation compiler available in F# PowerPack. However, as mentioned in the comments, it is definitely easier to use F# reflection:
open Microsoft.FSharp.Reflection
let applyOnFields (recd1:'T) (recd2:'T) f =
let flds1 = FSharpValue.GetRecordFields(recd1)
let flds2 = FSharpValue.GetRecordFields(recd2)
let flds = Array.zip flds1 flds2 |> Array.map f
FSharpValue.MakeRecord(typeof<'T>, flds)
This function takes records, gets their fields dynamically and then applies f to the fields. You can use it to imiplement your operator like this (I'm using a function with a readable name instead):
type R = { X : string ; Y : string }
let a = { X = null ; Y = "##" }
let b = { X = "##" ; Y = null }
let selectNotNull (x:obj, y) =
if String.IsNullOrWhiteSpace (unbox x) then y else x
let c = applyOnFields a b selectNotNull
The solution using Reflection is quite easy to write, but it might be less efficient. It requires running .NET Reflection each time the function applyOnFields is called. You could use quotations to build an AST that represents the function that you could write by hand if you knew the record type. Something like:
let applyOnFields (a:R) (b:R) f = { X = f (a.X, b.X); Y = f (a.Y, b.Y) }
Generating the function using quotations is more difficult, so I won't post a complete sample, but the following example shows at least a part of it:
open Microsoft.FSharp.Quotations
// Get information about fields
let flds = FSharpType.GetRecordFields(typeof<R>) |> List.ofSeq
// Generate two variables to represent the arguments
let aVar = Var.Global("a", typeof<R>)
let bVar = Var.Global("b", typeof<R>)
// For all fields, we want to generate 'f (a.Field, b.Field)` expression
let args = flds |> List.map (fun fld ->
// Create tuple to be used as an argument of 'f'
let arg = Expr.NewTuple [ Expr.PropertyGet(Expr.Var(aVar), fld)
Expr.PropertyGet(Expr.Var(bVar), fld) ]
// Call the function 'f' (which needs to be passed as an input somehow)
Expr.App(???, args)
// Create an expression that builds new record
let body = Expr.NewRecord(typeof<R>, args)
Once you build the right quotation, you can compile it using F# PowerPack. See for example this snippet.
I have a custom class in F# and I want to implement the [] list operator such that
let myClass = new myClassObj()
let someVal = myClass.[2]
I can't seem to find this on the web - I probably don't know the right term to search for... thanks in advance
You just need to implement an Item indexed property. E.g.
type MyClass() =
member x.Item with get(i:int) = (* some logic involving i here *)
If you start at the F# language reference, and go to members, one of the topics is indexed properties.
It is worth adding that F# also supports slicing syntax (which isn't mentioned on the indexed properites MSDN page). It means that you can index not only a single element such as m.[0] but also a slice such as m.[0..5] or an unbounded range m.[5..]. This is quite useful for various numerical data types (such as matrices).
To support this feature, the type must define GetSlice method. The following example demonstrates this using a 2D scenario:
type Foo() =
member x.GetSlice(start1, finish1, start2, finish2) =
let s1, f1 = defaultArg start1 0, defaultArg finish1 0
let s2, f2 = defaultArg start2 0, defaultArg finish2 0
sprintf "%A, %A -> %A, %A" s1 s2 f1 f2
> let f = new Foo()
f.[1.., 1..10];;
val it : string = "1, 1 -> 0, 10"
The arguments are of type int option and here we use defaultArg to specify 0 as the default value.