F# - Pattern matching discriminated union and accessing object's properties - f#

from F# tour i have this example
type Person = {
First : string
Last : string
}
/// A Discriminated Union of 3 different kinds of employees
type Employee =
| Engineer of engineer: Person
| Manager of manager: Person * reports: List<Employee>
| Executive of executive: Person * reports: List<Employee> * assistant: Employee
let rec findDaveWithOpenPosition(emps: List<Employee>) =
emps
|> List.filter(function
| Manager({First = "Dave"}, []) -> true
| Executive({First = "Dave"}, [], _) -> true
| _ -> false
)
However I would like to get access to object after matching object, something like this:
let rec findDaveWithOpenPos2(emps: List<Employee>) =
List.filter (fun (e:Employee) ->
match e with
| Manager({First = "Dave"}, []) -> e.Last.Contains("X") //Does not compile
| Executive({First = "Dave"}, [], _) -> true
| _ -> false
) emps
So i would like to have statically typed "e" as Person or Employee or Manager variable on right hand side with access to it's properties.
Is it possible? Is there a better construction?

You can name the Person instance within the Manager case using as:
let rec findDaveWithOpenPos2(emps: Employee list) =
List.filter (fun (e:Employee) ->
match e with
| Manager({First = "Dave"} as p, []) -> p.Last.Contains("X")
| Executive({First = "Dave"}, [], _) -> true
| _ -> false
) emps

Related

FsCheck lazy generators

I have issues with generation of data within my tests.
testProperty "calculate Operation against different operations should increase major" <| fun operationIdApi operationIdClient summaryApi summaryClient descriptionApi descriptionClient ->
( notAllEqual [
fun () -> assessEquality <| StringEquals(operationIdApi, operationIdClient)
fun () -> assessEquality <| StringEquals(summaryApi , summaryClient)
fun () -> assessEquality <| StringEquals(descriptionApi, descriptionClient)
]) ==> lazy (
let operationClient = createOpenApiOperation operationIdClient summaryClient descriptionClient
let operationAPI = createOpenApiOperation operationIdApi summaryApi descriptionApi
let actual = calculate operationAPI operationClient
Expect.equal actual (Fact.Semver.IncreaseMajor) "return IncreaseMajor"
)
The code that is actually tested is :
semver {
if operationAPI.OperationId<> operationClient.OperationId then yield! IncreaseMajor
if operationAPI.Summary <> operationClient.Summary then yield! IncreaseMajor
}
The test should fail when the data produced is same OperationId, same summary and different description.
But it does not and it led me to create my own generator or at least try to do so:
I wanted my test to be written like this :
testProperty "calculate Operation against different operations should increase major" <| fun (operationId:ElementSet<string>) (summary:ElementSet<string>) ->
Therefore I create a type accordingly:
type ElementSet<'a> =
| Same of 'a
| Different
and a generator for this type :
let setGen<'a> =
Gen.oneof [
gen {
let! v = Arb.generate<'a>
return Same(v)
}
gen { return Different}
]
type ElementSetGenerator =
static member ElementSet() =
Arb.fromGen setGen<'a>
do Arb.register<ElementSetGenerator>() |> ignore
I was then trying to extract the data to construct my object :
let createOpenApiOperation operationId summary=
let pi = OpenApiOperation(OperationId=operationId.Get, Summary=summary.Get)
pi
The Get method did not exist yet so I was about to implement it by adding a member to my ElementSet<'a>:
type ElementSet<'a> =
| Same of 'a
| Different
with member this.Get =
match this with
| Same s -> s
| Different -> Arb.generate<'a>// some random generation here
And this is where I am stuck. I would love to get some randomness here when I extract data. I wonder if this is the correct way to do so, or if I should have answered the problem earlier?
Thanks for your inputs.
I think I found it, the answer was to handle it at the beginning :
let setGen<'a when 'a:equality> =
Gen.oneof [
gen {
let! v = Arb.generate<'a>
return Same(v)
}
gen {
let! x,y =
Arb.generate<'a>
|> Gen.two
|> Gen.filter (fun (a,b)-> a <> b)
return Different(x,y)
}
]
and then to use two getter to access the values :
type ElementSet<'a> when 'a:equality=
| Same of 'a
| Different of 'a*'a
with member this.Fst = match this with | Same s -> s | Different (a, b)-> a
member this.Snd = match this with | Same s -> s | Different (a, b)-> b
this way I can access values within my test:
testProperty "calculate Operation against different operations should increase major" <| fun (operationId:ElementSet<NonWhiteSpaceString>) (summary:ElementSet<NonWhiteSpaceString>) (description:ElementSet<NonWhiteSpaceString>) ->
let operationClient = createOpenApiOperation operationId.Fst summary.Fst description.Fst
let operationAPI = createOpenApiOperation operationId.Snd summary.Snd description.Snd
let actual = calculate operationAPI operationClient
Expect.equal actual (Fact.Semver.IncreaseMajor) "return IncreaseMajor"
for the record I then have the creation of my stub as follows :
let createOpenApiOperation (operationId:NonWhiteSpaceString) (summary:NonWhiteSpaceString) (description:NonWhiteSpaceString)=
let pi = OpenApiOperation(OperationId=operationId.Get, Summary=summary.Get, Description=description.Get)
pi

Construct generic function

I have a type:
type DictionaryCache<'a, 'b when 'a :comparison>()
And I have another type which contains some of this DictionaryCache:
type Cache() =
let user = new DictionaryCache<int, User>()
let userByLogin = new DictionaryCache<string, User>()
member this.User = user
member this.UserByLogin = userByLogin
In the last type I want to create generic function which will return one of the members based on input parameter:
member this.CacheNameToDictionary (cacheName: string) : DictionaryCache<'a, 'b> option =
match cacheName with
| "userByAutoincrementedId" -> Some(this.User)
| "userByLogin" -> Some(this.UserByLogin)
| _ -> None
But it doesn't work because of type mismatch.
Is there any way to rewrite this function ?
Update: here is a full code what I need to do:
type Cache() =
let user = new DictionaryCache<int, User>()
let userByLogin = new DictionaryCache<string, User>()
static let mutable instance = lazy(new Cache())
static member Instance with get() = instance.Value
member this.User = user
member this.UserByLogin = userByLogin
member this.Get (useCache: string) (cacheName: string) (id: 'a) longFunction exceptionFunction : 'b option =
let nameToDictionary() : DictionaryCache<'a, 'b> option =
match cacheName with
| "userByAutoincrementedId" -> Some(this.User)
| "userByLogin" -> Some(this.UserByLogin)
| _ -> None
let foo() : 'b option =
try
longFunction()
with
| exn -> exceptionFunction exn
None
match (useCache, nameToDictionary()) with
| "true", Some(dictionary) ->
match dictionary.Get id with
| Some(result) -> Some(result)
| _ -> match foo() with
| Some(result) -> dictionary.Put id result
Some(result)
| _ -> None
| _ -> foo()
This is not possible - the problem is that the return type of the method would depend on the string that it gets as the input argument. The input string is only known at run-time, but the type needs to be known at compile-time.
You could use the Choice type which lets you return one of multiple different types:
member this.CacheNameToDictionary (cacheName: string) =
match cacheName with
| "userByAutoincrementedId" -> Choice1Of3(this.User)
| "userByLogin" -> Choice2Of3(this.UserByLogin)
| _ -> Choice3Of3()
This works, but the return type lists all three alternatives and is pretty ugly:
Choice<DictionaryCache<int,User>, DictionaryCache<string,User>,unit>
Also, the consumer of this method will have to pattern match on the result and handle the two different dictionaries in different ways, so this might not make your code particularly beautiful.
Honestly, I think that you are adding a level of abstraction that you do not need. If there are two different keys, then you need different code to handle that and it's unlikely that you'll be able to write code that is extensible and adds third kind of dictionary.

How to do pattern matching in Rx. Where and Select in a single operator?

Suppose I have this type:
type T = int option
and an observable of that type:
let o : IObservable<T> = // create the observable
I'm looking for a better way to express this:
o.Where(function | None -> false | Some t -> true)
.Select(function | Some t -> t)
An observable that only propagates the Some case.
There are several things that I don't like.
I'm using 2 operators
I'm pattern matching twice
The second pattern matching isn't exhaustive (makes visual studio show a warning and feels odd)
Too much code. The pattern repeats every time I need pattern matching.
Can't you use Observable.choose ? something like this :
let o1 : IObservable<int option> = // ...
let o2 = Observable.choose id o1
If you have a type that is not an option, say:
type TwoSubcases<'a,'b> = | Case1 of 'a | Case2 of 'b
and a partial active pattern:
let (|SecondCase|_|) = function
| Case1 _ -> None
| Case2 b -> Some b
then you can do:
let o1 : IObservable<TwoSubcases<int, float>> = // ...
let o2 : IObservable<float> = Observable.choose (|SecondCase|_|) o1
Thanks to #Lee I came up with a nice solution.
o.SelectMany(function | None -> Observable.Empty() | Some t -> Observable.Return t)
This works for any union type, not only Option.

Type inference failure with F# gives an unclear error

I have the following ViewModelBase in F# which I'm trying to build to learn F# with WPF.
module MVVM
open System
open System.Collections.ObjectModel
open System.ComponentModel
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open System.Reactive.Linq
module Property =
let ToName(query : Expr) =
match query with
| PropertyGet(a, b, list) ->
b.Name
| _ -> ""
let SetValue<'t>(obj, query : Expr<'t>, value : 't) =
match query with
| PropertyGet(a, b, list) ->
b.SetValue(obj, value)
| _ -> ()
let GetValue<'o, 't>(obj : 'o , query : Expr<'t>) : option<'t> =
match query with
| PropertyGet(a, b, list) ->
option.Some(b.GetValue(obj) :?> 't )
| _ -> option.None
let Observe<'t>(x: INotifyPropertyChanged) (p : Expr<'t>) =
let name = ToName(p)
x.PropertyChanged.
Where(fun (v:PropertyChangedEventArgs) -> v.PropertyName = name).
Select(fun v -> GetValue(x, p).Value)
type ViewModelBase() =
let propertyChanged = new Event<_, _>()
interface INotifyPropertyChanged with
[<CLIEvent>]
member x.PropertyChanged = propertyChanged.Publish
abstract member OnPropertyChanged: string -> unit
default x.OnPropertyChanged(propertyName : string) =
propertyChanged.Trigger(x, new PropertyChangedEventArgs(propertyName))
member x.SetValue<'t>(expr : Expr<'t>, v : 't) =
Property.SetValue(x, expr, v)
x.OnPropertyChanged(expr)
member x.OnPropertyChanged<'t>(expr : Expr<'t>) =
let propName = Property.ToName(expr)
x.OnPropertyChanged(propName)
However I get an error from the compiler
Error 1 The type 'ViewModelBase' is used in an invalid way.
A value prior to 'ViewModelBase' has an inferred type involving
'ViewModelBase', which is an invalid forward reference.
However the compiler doesn't tell me what value prior is the offending part of the problem. As I'm pretty new to the type inference as used by F# I'm probably missing an obvious problem.
FYI the code is meant to be used like the below but at the moment this code is commented out and the error is only pertaining to the core code above
type TestModel() as this =
inherit MVVM.ViewModelBase()
let mutable name = "hello"
let subscription = (Property.Observe this <# this.SelectedItem #>).
Subscribe(fun v -> Console.WriteLine "Yo")
member x.SelectedItem
with get() = name
and set(v) =
x.SetValue(<# x.SelectedItem #>, v)
I found it.
let SetValue<'t>(obj, query : Expr<'t>, value : 't) =
match query with
| PropertyGet(a, b, list) ->
b.SetValue(obj, value)
| _ -> ()
was under constrained. Should be
let SetValue<'t>(obj : Object, query : Expr<'t>, value : 't) =
match query with
| PropertyGet(a, b, list) ->
b.SetValue(obj, value)
| _ -> ()

Avoiding nested pattern matching (possibly with maybe monad)

How could nested pattern matching, such as the following example, be re-written so that None is specified only once? I think the Maybe monad solves this problem. Is there something similar in the F# core library? Or, is there an alternative approach?
match a with
| Some b ->
let c = b.SomeProperty
match c with
| Some d ->
let e = d.SomeProperty
//and so on...
| None -> ()
| None -> ()
you can solve this using built-in capabilities: Option.bind
type A =
member this.X : B option = Unchecked.defaultof<_>
and B =
member this.Y : С option = Unchecked.defaultof<_>
and С =
member this.Z : string option = Unchecked.defaultof<_>
let a : A = Unchecked.defaultof<_>
let v =
match
a.X
|> Option.bind (fun v -> v.Y)
|> Option.bind (fun v -> v.Z) with
| Some s -> s
| None -> "<none>"
Frankly, I doubt that introducing full-fledged 'maybe' implementation (via computation expressions) here can shorten the code.
EDIT: Dream mode - on
I think that version with Option.bind can be made smaller if F# has more lightweight syntax for the special case: lambda that refer to some member of its argument:
"123" |> fun s -> s.Length // current version
"123" |> #.Length // hypothetical syntax
This is how the sample can be rewritten in Nemerle that already has such capabilities:
using System;
using Nemerle.Utility; // for Accessor macro : generates property for given field
variant Option[T]
{
| Some {value : T}
| None
}
module OptionExtensions
{
public Bind[T, U](this o : Option[T], f : T -> Option[U]) : Option[U]
{
match(o)
{
| Option.Some(value) => f(value)
| Option.None => Option.None()
}
}
}
[Record] // Record macro: checks existing fields and creates constructor for its initialization
class A
{
[Accessor]
value : Option[A];
}
def print(_)
{
// shortened syntax for functions with body -> match over arguments
| Option.Some(_) => Console.WriteLine("value");
| Option.None => Console.WriteLine("none");
}
def x = A(Option.Some(A(Option.Some(A(Option.None())))));
print(x.Value.Bind(_.Value)); // "value"
print(x.Value.Bind(_.Value).Bind(_.Value)); // "none"
I like desco's answer; one should always favor built-in constructs. But FWIW, here's what a workflow version might look like (if I understand the problem correctly):
type CE () =
member this.Bind (v,f) =
match v with
| Some(x) -> f x
| None -> None
member this.Return v = v
type A (p:A option) =
member this.P
with get() = p
let f (aIn:A option) = CE () {
let! a = aIn
let! b = a.P
let! c = b.P
return c.P }
let x = f (Some(A(None)))
let y = f (Some(A(Some(A(Some(A(Some(A(None)))))))))
printfn "Your breakpoint here."
I don't suggest this, but you can also solve it with exception handling:
try
<code that just keeps dotting into option.Value with impunity>
with
| :? System.NullReferenceException -> "None"
I just wanted to point out the rough equivalence of exception-handling to the Maybe/Either monads or Option.bind. Typically prefer one of them to throwing and catching exceptions.
Using Option.maybe from FSharpx:
open FSharpx
type Pet = { Name: string; PreviousOwner: option<string> }
type Person = { Name: string; Pet: option<Pet> }
let pers = { Name = "Bob"; Pet = Some {Name = "Mr Burns"; PreviousOwner = Some "Susan"} }
Option.maybe {
let! pet = pers.Pet
let! prevOwner = pet.PreviousOwner
do printfn "%s was the previous owner of %s." prevOwner pet.Name
}
Output:
Susan was the previous owner of Mr Burns.
But, e.g. with this person instead there is just no output:
let pers = { Name = "Bob"; Pet = None }

Resources