Is there a better way to write the addValues function below? It seems it should be possible to use pattern matching rather than FSharp.Reflection but I can't see it.
open System
open FSharp.Reflection
type Value =
| Tag1 of decimal
| Tag2 of decimal
| Error of string
let addValues v1 v2 =
let c1, f1 = FSharpValue.GetUnionFields(v1, v1.GetType())
let c2, f2 = FSharpValue.GetUnionFields(v2, v2.GetType())
let amt1 = (f1.[0]) :?> decimal
let amt2 = (f2.[0]) :?> decimal
if c1 = c2
then ((FSharpValue.MakeUnion(c1, [|box (amt1 + amt2)|]))) :?> Value
else Error "Mixed Tags"
This can be used like so:
addValues (Tag1 22m) (Tag1 10m) //Value = Tag1 32M
addValues (Tag1 22m) (Tag2 10m) //Value = Error "Mixed Tags"
It's not clear how addValues (Error "e1") (Error "e2) should be handled but for the other cases you can do:
let addValues v1 v2 =
match v1, v2 with
| Tag1 d1, Tag1 d2 -> Tag1 (d1 + d2)
| Tag2 d1, Tag2 d2 -> Tag2 (d1 + d2)
| Error e1, Error e2 -> //???
| _ -> Error "Mixed Tags"
This is not precisely what the original question was about, but - as some other commenters - I have a hunch that your datatypes are not really well chosen. Having an Error case means that, the moment you have more tags, your addValues function becomes really awkward. If I assume that all your values are decimal, you could re-define as follows:
type Tag = | Tag1 | Tag2
type ResultOrError = | Result of Tag * decimal | Error of string
(or use one of the Choice types). addValues then becomes:
let addValues t1 t2 =
match t1, t2 with
| Result (tag1, v1), Result (tag2, v2) when tag1 = tag2 -> Result (tag1, v1 + v2)
| Result _, Result _ -> Error "Tag mismatch"
| Result _, Error _ -> failwith "not implemented"
| Error _, _ -> failwith "not implemented"
The moment you extend your tags type to type Tag = | Tag1 | Tag2 | Tag3, addValues remains still working.
I'd like to blow the same trumpet as Anton Schwaighofer in his answer. The crucial piece of information has to be inside the data structure, because this will leverage monad techniques to do the lifting; also you would otherwise need separate calls to the constructors of the cases Tag1 and Tag2.
type Tag = Tag1 | Tag2
type ResultOrError =
| Result of Tag * decimal
| Error of string
let bind2 f = function
| Result(tag, value) -> f tag value
| error -> error
let lift2EqualTag op mx my =
bind2 (fun tagX x ->
bind2 (fun tagY y ->
if tagX = tagY then Result(tagX, op x y)
else Error "Mixed tags" ) my ) mx
let add = lift2EqualTag (+)
add (Result(Tag1, 22m)) (Result(Tag1, 10m))
// val it : ResultOrError = Result (Tag1,32M)
add (Result(Tag1, 22m)) (Result(Tag2, 10m))
// val it : ResultOrError = Error "Mixed tags"
Related
I implemented a Discriminated Union type that would be used to select a function:
type BooleanCombinator =
| All
| Some
| None
| AtLeast of int
| MoreThan of int
| NotMoreThan of int
| LessThan of int
| ExactlyOne
| ExactlyTwo
| AllButOne
| AllButTwo
let boolToInt (b: bool) : int = if b then 1 else 0
let combineBooleans (combinator : BooleanCombinator)
(bools : bool list)
: bool =
let n = List.sumBy boolToInt bools
match combinator with
| BooleanCombinator.All -> List.forall id bools
| BooleanCombinator.Some -> bools |> List.exists id
| BooleanCombinator.None -> bools |> List.exists id |> not
| BooleanCombinator.AtLeast i -> n >= i
| BooleanCombinator.MoreThan i -> n > i
| BooleanCombinator.NotMoreThan i -> n <= i
| BooleanCombinator.LessThan i -> n < i
| BooleanCombinator.ExactlyOne -> n = 1
| BooleanCombinator.ExactlyTwo -> n = 2
| BooleanCombinator.AllButOne -> n = bools.Length - 1
| BooleanCombinator.AllButTwo -> n = bools.Length - 2
This looked Ok to me but the compiler started to look at all instances of Some and None as belonging to this DU, instead of the Option DU.
I do not want to go through all of my code replacing Some with Option.Some and None with Option.None.
Is there a way to tell the compiler that unqualified Some and None are actually Option.Some and Option.None?
Or should I just give different names to these DU cases, like AtLeastOne and ExactlyZero
The general rule for resolving name collisions in F# is "last declaration wins". Because your custom DU is declared after Option, its constructors Some and None win over those of Option.
But this rule offers a way to fix the problem: you just need to "reassert" the declarations after your custom DU:
type Bogus = Some of int | None
let g = function Some _ -> 42 | None -> 5
let x = Some 42
let inline Some a = Option.Some a
let inline None<'a> = Option.None : 'a option
let (|Some|None|) = function | Option.Some a -> Some a | Option.None -> None
let f = function Some _ -> 42 | None -> 5
let y = Some 42
If you inspect the types of g, x, f, and y in the above code:
> g
g : Bogus -> int
> f
f : 'a option -> int
> x
Bogus
> y
int option
The function g and value x were inferred to have type Bogus -> int and Bogus respectively, because Some and None in their bodies refer to Bogus.Some and Bogus.None.
The function f and value y were inferred to have Option-related types, because Some and None in their bodies refer to the Some function and the (|Some|None|) active pattern that I defined just above.
Of course, this is a rather hacky way to restore status quo. This will convince the compiler, but humans will still have a hard time reading your code. I suggest you rename the cases of your DU instead.
You can mark your DU with [<RequireQualifiedAccess>] attribute.
This means that you will be required to qualify the case name with the type whenever you use it in the code - which is something you do now anyway in your match expression.
That way an unqualified Some would still be resolved to mean Option.Some, despite the fact that you reuse the name.
It's a useful technique to know when you want to use a snappy name for a DU case - like None, Yes, Failure etc. - that by itself would be ambiguous or confusing to the reader (or the compiler, for that matter).
I'm trying to create DU cases from strings. The only way I can see doing this is by enumerating over the DU cases via Microsoft.FSharp.Reflection.FSharpType.GetUnionCases and then picking the UnionCase that matches the string (by using .Name) and then making the actual DU case out of that by using FSharpValue.MakeUnion.
Isn't there an easier/more elegant way of doing this? In my scenario I have a DU with a couple of hundred cases for keywords. I have to read the strings (keywords) from a file and make the types out of them. I did some "optimization" by putting the cases into a Map but I was hoping there'd be a better way of doing this.
I have the following, for example:
type Keyword =
| FOO
| BAR
| BAZ
| BLAH
let mkKeywords (file: string) =
use sr = new StreamReader(file)
let caseMap =
FSharpType.GetUnionCases(typeof<Keyword>)
|> Array.map (fun c -> (c.Name, FSharpValue.MakeUnion(c, [||]) :?> Keyword))
|> Map.ofArray
[
while not sr.EndOfStream do
let l = sr.ReadLine().Trim()
match caseMap.TryFind l with
| Some c -> yield c
| None -> failwith <| "Could not find keyword: " + l
]
I found this handy code snippet...
open Microsoft.FSharp.Reflection
let toString (x:'a) =
let (case, _ ) = FSharpValue.GetUnionFields(x, typeof<'a>)
case.Name
let fromString<'a> (s:string) =
match FSharpType.GetUnionCases typeof<'a> |> Array.filter (fun case -> case.Name = s) with
|[|case|] -> Some(FSharpValue.MakeUnion(case,[||]) :?> 'a)
|_ -> None
... which makes it easy to tack on two lines of code to any DU...
type A = X|Y|Z with
override this.ToString() = FSharpUtils.toString this
static member fromString s = FSharpUtils.fromString<A> s
I would use pattern matching like this:
type Keyword =
| FOO
| BAR
| BAZ
| BLAH
let matchKeyword (word:string) : Keyword option =
match word with
| "FOO" -> Some FOO
| "BAR" -> Some BAR
| "BAZ" -> Some BAZ
| "BLAH" -> Some BLAH
| _ -> None
And maybe auto generate the match statement first time using regex in my editor, but only because you have hundreds of cases. But i am not sure if its a better solution then yours.
As the cases have no value, another option is to use enums:
type Keyword =
| FOO = 0
| BAR = 1
| BAZ = 2
| BLAH = 3
let strings = ["FOO";"BAR"]
let keywords =
[for s in strings -> s, Keyword.Parse(typeof<Keyword>, s)]
|> Map.ofList
Then you can simply use Enum.Parse.
I have a discriminated union, such as
type Dish =
| Eggs
| Spam of Dish
This is basically a linked list, without any content, e.g. Spam(Spam(Spam(Eggs))). I want to strictly perform a computation on this structure, such as counting the length, and memorize the result. In a normal type, I'd use class-local let bindings, but those aren't available in discriminated unions.
One way to do this would be,
type Count = int
type Dish =
| Eggs
| Spam of Dish * Count
But this is really messy, when the data I need is easily computable, but I still hope there is a better way (without using external mutable constructs).
One option is making the union cases private to hide the cached length.
//the 'guts' of Dish -- entirely hidden
type private DishImpl =
| Eggs
| Spam of DishImpl
// Dish wrapper type -- implementation hidden
type Dish =
private
| Dish of DishImpl * int
with
// O(1), just get the 'length' field
member x.Length = let (Dish(_, len)) = x in len
static member Eggs() = Dish(Eggs, 1)
static member Spam(Dish(dish, len)) = Dish(Spam dish, len + 1)
let eggs = Dish.Eggs()
let spam = Dish.Spam(eggs)
printfn "%d" eggs.Length //outputs: 1
printfn "%d" spam.Length //outputs: 2
To do it up right, create an accompanying module with let-bound functions and active patterns for destructuring.
If you tolerate a bit internal mutable state, here is a memoize function which creates a dictionary per function:
let memoize f =
let dict = Dictionary()
fun n ->
match dict.TryGetValue(n) with
| (true, v) -> v
| _ ->
let res = f(n)
dict.Add(n, res)
res
// This function results in a warning though
let rec length = memoize (function Eggs -> 0 | Spam d -> 1 + length d)
The approach isn't that bad since the mutable dictionary is hidden.
A purely functional approach could be using Map to hold values and a kind of State computation expression to hide Map values passing around. Please refer to this snippet to see how a memoize computation expression looks like.
There is also Memo Functions, Polytypically! by Ralph Hinze (2000). Adapting to F#:
type Dish =
| Eggs
| Spam of Dish
type DishTable<'T> =
{
Eggs : Lazy<'T>
Spam : Lazy<DishTable<'T>>
}
let rec tabulate (f: Dish -> 'T) : DishTable<'T> =
{
Eggs = lazy f Eggs
Spam = lazy tabulate (f << Spam)
}
let rec lookup (table: DishTable<'T>) (dish: Dish) : 'T =
match dish with
| Eggs -> table.Eggs.Value
| Spam x -> lookup table.Spam.Value x
let memo (f: Dish -> 'T) : (Dish -> 'T) =
lookup (tabulate f)
let rec len x =
match x with
| Eggs -> 0
| Spam x -> 1 + len x
let l2 = memo len
This is what I came up with. It's not true memoization because it counts eagerly when you call mem, but might work for your needs.
type Dish =
| Eggs
| Spam of Dish
| Memo of Dish * int
with
member d.length =
match d with
| Eggs -> 1
| Spam d -> 1 + d.length
| Memo (d, i) -> i
member d.mem =
match d with
| Eggs -> Memo(d, d.length)
| Spam d2 -> Memo(d, d.length)
| Memo(d2, i) -> d // no need to memo it again
let x = Spam (Spam(Spam Eggs))
let m = x.mem
x.length // val it : int = 4
m.length // val it : int = 4
Note that in your case, literally the only interesting property of a value of your type is its length, so you might as well just use integers as your representation instead:
let Eggs = 0
let Spam n = 1 + n
let (|Eggs|Spam|) = function
| 0 -> Eggs
| n -> Spam(n-1)
let length = id
// example usage
let dish = Spam(Spam(Eggs))
let l = length dish
let kind =
match dish with
| Eggs -> "Eggs"
| Spam(Eggs) -> "One Spam"
| Spam(Spam _) -> "At least two Spams"
If your real question is how to do this for a more interesting type, then one approach would be to create mutually recursive types, one of which is annotated:
type 'a AnnotatedDish = { dish : 'a Dish; value : 'a }
and 'a Dish =
| Eggs
| Spam of 'a AnnotatedDish
// "smart" constructors, given that you want to annotate with length
let eggs = { dish = Eggs; value = 0 }
let spam d = { dish = Spam d; value = 1 + d.value }
let length { value = l } : int = l
// active patterns
let (|Eggs|Spam|) = function
| { dish = Eggs } -> Eggs
| { dish = Spam d } -> Spam d
// example usage
let dish = spam(spam(eggs))
let l = length dish
let kind =
match dish with
| Eggs -> "Eggs"
| Spam(Eggs) -> "One Spam"
| Spam(Spam _) -> "At least two Spams"
After reviewing the answers, I've decided to go with a model that seems the least obtrusive to me. I've used a modified object to demonstrate how it would work in a slightly more complex scenario.
type StackDef<'a>(v : 'a, s : Stack<'a>) =
member val Length = s.Length + 1
member val Inner = v, s
and Stack<'a> =
| Empty
| Stack of StackDef<'a>
member this.Length =
match this with
| Empty -> 0
| Stack(def) -> def.Length
let Stack (v, s) = Stack(StackDef(v, s))
let (|Stack|Empty|) = function | Empty -> Empty | Stack(sd) -> Stack(sd.Inner)
//...
let example = Stack(1, Stack(2, Stack(3, Empty))).Length
It doesn't contain any external mutable state.
The discriminated union Dish (or in the example, Stack) continues to exist.
The field length doesn't appear in the union definition at all, nor is it provided by any constructor, just as it should be.
The memoized data is associated with the instance, as it should be.
However, having thought about it, by using a static weaver such as Afterthought it might be possible to replace any method such as:
Stack<'a> =
| Empty
| Stack of 'a * Stack<'a>
[<Lazy>] //custom attribute that would work with a static weaver
member this.Length =
match this with
| Empty -> 0
| Stack(_, s) -> s.Length + 1
With a private readonly Lazy<int> __length initialized in the constructor with a delegate that executes the above code, and change the actual content of the method to simply invoking __length.Value.
While F# doesn't allow union types to contain fields, possibly for very valid reasons, I highly doubt the IL would have such restrictions.
In fact, it would be possible to do a lot of things using some IL manipulation. Maybe it's something to think about.
In F# code I have a tuple:
let myWife=("Tijana",32)
I want to access each member of the tuple separately. For instance this what I want to achieve by I can't
Console.WriteLine("My wife is {0} and her age is {1}",myWife[0],myWife[1])
This code doesn't obviously work, by I think you can gather what I want to achieve.
You want to prevent your wife from aging by making her age immutable? :)
For a tuple that contains only two members, you can fst and snd to extract the members of the pair.
let wifeName = fst myWife;
let wifeAge = snd myWife;
For longer tuples, you'll have to unpack the tuple into other variables. For instance,
let _, age = myWife;;
let name, age = myWife;;
Another quite useful thing is that pattern matching (just like when extracting elements using "let" binding) can be used in other situations, for example when writing a function:
let writePerson1 person =
let name, age = person
printfn "name = %s, age = %d" name age
// instead of deconstructing the tuple using 'let',
// we can do it in the declaration of parameters
let writePerson2 (name, age) =
printfn "name = %s, age = %d" name age
// in both cases, the call is the same
writePerson1 ("Joe", 20)
writePerson2 ("Joe", 20)
You can use the function fst to get the first element, and snd to get the second ekement. You can also write your own 'third' function:
let third (_, _, c) = c
Read more here: F# Language reference, Tuples
You can also write an unpack function for a certain length:
let unpack4 tup4 ind =
match ind, tup4 with
| 0, (a,_,_,_) -> a
| 1, (_,b,_,_) -> b
| 2, (_,_,c,_) -> c
| 3, (_,_,_,d) -> d
| _, _ -> failwith (sprintf "Trying to access item %i of tuple with 4 entries." ind)
or
let unpack4 tup4 ind =
let (a, b, c, d) = tup4
match ind with
| 0 -> a
| 1 -> b
| 2 -> c
| 3 -> d
| _ -> failwith (sprintf "Trying to access item %i of tuple with 4 entries." ind)
I'm fairly new to F# and I wanted to compare two values with the (match ... with ...) syntax
The problem arises when I attempt to compare two values like this:
let value1 = 19
let isValue1 y =
match y with
| value1 -> y + 1
| _ -> y
I get a warning that the "| _ -> y" portion of the code will never be reached. Why is this?
I know that I can do the following to get the function to work the way I want it to:
let value1 = 19
let isValue1 y =
match y with
| _ when y = value1 -> true
| _ -> false
This works as well
let value1 = 19
let isValue1 y =
match y with
| 19 -> true
| _ -> false
I'm just curious about why I can't do that, and how match actually works.
The value1 within the match statement is defined as a new variable, the value of which is set to y (as a match). The value1 you define just above is ignored, just as if you were declaring a local variable in a C# function with the same name as a class variable. For this reason, the first match condition will match everything, not just the previously defined value of value1, hence the error. Hope that clarifies matters.
Pattern-matching is both a control construct (what code executes next) and a binding construct (like 'let', bind a name to a value). So when you do
match expr with
| name -> ...
the pattern ("name") always matches and the identifier 'name' just gets bound to the value of the expression. This is why pattern-matching is mostly used with discriminated unions (case types), where you match based on the structure. E.g.
match someOption with
| Some(x) -> ... // binds x
| None -> ...
match someList with
| h :: t -> ... // binds h and t to head/tail
| [] -> ...
You can just match the Input to Literals/Identifiers marked by the [<Literal>] Attribute without binding it.
For Example:
#light
[<Literal>]
let E = 2.718281828459
let isE x =
match x with
| E -> true
| _ -> false
print_any (isE 3.2)
print_any (isE E)
According to Crish Smith