Playing with F# types and getting lost - f#

I have been doing a little reading on F# and decided to give it a try. I started with a somewhat involved example and I came up with and got lost immediately. I wonder if someone can share some thoughts on it.
I wanted to write a method called ComparisonStrategy<'T> that returns an instance of IEqualityComparer<'T>. It that takes in a variable length of ComparisonWhichAndHow<'T> instances. The type ComparisonWhichAndHow<'T> can either be:
One function of type ('T -> *), which is a method that selects a single field to compare
a 2-tuple of ('T -> 'U, IEqualityComparer<'U>) if you don't want the default Equals or GetHashCode to be used on 'U.
I have tried to draw this down on visual studio for a while now, but I can't even get the function declaration part right. I am somewhat positive I would be able to implement the method body if I can just get past this, but seems like I can't.
Edited:
This is the code I have tried so far.
I am trying to achieve the 2 following things.
Come up with a generic way of generating a equal method for each object.
Sometimes some business operations might require comparing some fields of 2 objects, and some fields of their children. Not a full comparison. I am trying to make writing those code more concise and simple
This is what I have so far:
module Failed =
open System.Collections.Generic
open System
type ComparsionOption<'T, 'U> =
| Compare of ('T -> 'U)
| CompareWith of ('T -> 'U) * IEqualityComparer<'U>
// TO USE: [<ParamArray>]
// TODO: this method returns a dummy for now
let CompareStrategy (opts : ComparsionOption<'T, _> array) =
EqualityComparer<'T>.Default
// How it's used
type Person(name : string, id : Guid) =
member this.Name = name
member this.ID = id
let fullCompare : EqualityComparer<Person> =
CompareStrategy [|Compare(fun (p : Person) -> p.Name);
CompareWith((fun (p : Person) -> p.ID), EqualityComparer<Guid>.Default)|] // error here

Looking at the problem from another perspective, it looks like you want to be able to construct objects that perform comparison in two different ways (which you specified) and then compose them.
Let's start by looking at the two ways to build an object that performs comparison. You can represent both by IEqualityComparer<'T>. The first one takes a function 'T -> Something and performs comparison on the result. You can define a function like this:
/// Creates a comparer for 'T values based on a predicate that
/// selects some value 'U from any 'T value (e.g. a field)
let standardComparer (f:'T -> 'U) =
{ new IEqualityComparer<'T> with
member x.Equals(a, b) =
(f a).Equals(b) // Call 'f' on the value & test equality of results
member x.GetHashCode(a) =
(f a).GetHashCode() } // Call 'f' and get hash code of the result
The function is 'T -> 'U using F# generics, so you can project fields of any type (the type just has to be comparable). The second primitive function also takes 'T -> 'U, but it also takes a comparer for 'U values instead of using the default:
/// Creates a comparer for 'T values based on a predicate & comparer
let equalityComparer (f:'T -> 'U) (comparer:IEqualityComparer<'U>) =
{ new IEqualityComparer<'T> with
member x.Equals(a, b) =
comparer.Equals(f a, f b) // Project values using 'f' and use 'comparer'
member x.GetHashCode(a) =
comparer.GetHashCode(f a) } // Similar - use 'f' and 'comparer'
Now you're saying that you'd like to take a sequence of values created in one of the two above ways to build a single comparison strategy. I'm not entirely sure what you mean by that. Do you want two objects to be equal when all the specified comparers report them as equal?
Assuming that is the case, you can write a function that combines two IEqualityComparer<'T> values and reports them as equal when both comparers report them as equal like this:
/// Creates a new IEqualityComparer that is based on two other comparers
/// Two objects are equal if they are equal using both comparers.
let combineComparers (comp1:IEqualityComparer<'T>) (comp2:IEqualityComparer<'T>) =
{ new IEqualityComparer<'T> with
member x.Equals(a, b) =
comp1.Equals(a, b) && comp2.Equals(a, b) // Combine results using &&
member x.GetHashCode(a) =
// Get hash code of a tuple composed by two hash codes
hash (comp1.GetHashCode(a), comp2.GetHashCode(a)) }
This is essenitally implementing all the functionality that you need. If you have some object Person, you can construct comparer like this:
// Create a list of primitive comparers that compare
// Name, Age and ID using special 'idComparer'
let comparers =
[ standardComparer (fun (p:Person) -> p.Name);
standardComparer (fun (p:Person) -> p.Age);
equalityComparer (fun (p:Person) -> p.ID) idComparer ]
// Create a single comparer that combines all of them...
let comparePerson = comparers |> Seq.reduce combineComparers
You could wrap this in a more object-oriented interface using overloaded methods etc., but I think that the above sample shows all the important components that you'll need in the solution.
BTW: In the example, I was using F# object expressions to implement all the functions.

Related

F# Use base type of discriminated union

I'm learning F# and struggling trying to use discriminated unions. I have a simple case where I'm trying to use Map.map on a simple discriminated union of the type Map but its saying there is a type mismatch. I'm basically just trying to use the type Prices as a Map
Here is a simplified example:
type Prices = Prices of Map<string, int>
let GetSalePrice (prices: Prices) = prices |> Map.map (fun k v -> (k, v * 2))
Gives me this error:
/Users/luke/code/chronos/Chronos.Mining/Chronos.Mining.Actors/Untitled-1(22,47): error FS0001: Type mismatch. Expecting a
'Prices -> 'a'
but given a
'Map<'b,'c> -> Map<'b,'d>'
The type 'Prices' does not match the type 'Map<'a,'b>'
Given that all I'm doing in the map function is returning the value * 2 I don't understand why I'm getting this error.
You cannot "use Prices as a Map", because Prices is not a Map. The way you have defined it, Prices is a different type, not at all the same as a Map, but it contains an instance of a Map inside it.
If this is indeed what you meant, then in order to get the Map out of a Prices value, you need to pattern-match on it. Like this:
let GetSalePrice (Prices theMap) = theMap |> Map.map ...
Whoa, what's going on here? How is Prices theMap different from prices: Prices? Why are we putting the type name in front of the parameter rather than behind it via a colon? Isn't that how types are denoted in F#?
You may have a bit of a confusion because you're using the same name Prices for both the type and its constructor. To clear this up, let me redefine your type like this:
type PricesType = PricesCtor of Map<string, int>
Now the function would look like:
let GetSalePrice (PricesCtor theMap) = theMap |> Map.map ...
So you see, it's not the type that we're putting in front of the parameter. It's the constructor. And this declaration - (PricesCtor theMap) - tells the compiler that we're expecting a parameter of type PricesType (because that's where PricesCtor belongs), and when we get this parameter, it should be unwrapped, and the map contained within should be named theMap.
This whole process is called "pattern matching". Here, we're matching on the constructor PricesCtor.
Your original function, on the other hand, merely specified the type of the parameter. With my new type definition I might write your original function like this:
let GetSalePrice (prices: PricesType) = prices |> Map.map ...
Here, we specify that our parameter should have type PricesType, but then we're trying to use it as an argument for Map.map, which expects a parameter of type Map<_,_>. No wonder there is a type mismatch!
Pattern matching doesn't have to be in the parameter declaration either. You can pattern-match anywhere in the code. To do that, use the match keyword. This is how your function may be written that way:
let GetSalePrice prices =
match prices with
| PricesCtor theMap -> theMap |> Map.map ...
The match keyword becomes significant as soon as your type has more than one constructor. For example:
type PricesType = PricesAsAMap of Map<string, int> | SinglePrice as int
In this case, if you specify the pattern in the parameter declaration:
let GetSalePrice (PricesAsAMap theMap) = ...
the compiler will warn you that the pattern match is incomplete. Indeed, your function knows what to do when given a SinglePrice value, but what should it do when given a ConstantPrice? You haven't defined that, so the compiler will complain.
This setup is an occasion to use the match keyword:
let GetSalePrice prices =
match prices with
| PricesAsAMap theMap -> theMap |> Map.map ...
| SinglePrice p -> "single item", p

F# Type Inference Odd Behavior With Records

I am in the process of learning F# and I am trying to wrap my head around as to why, when I override the inferred type with the correct type, that it infers a different type with List.Filter. Code is worth a thousand words:
type Account =
{ account : int
label : string }
type Journal =
{ account : int
period : string
debit : int
credit : int }
let outputJournal (journals: Journal List) (account:Account) =
let filtered = List.filter (fun x -> x.account = account.account) journals
filtered
I need to filter a list of journals against the specified account. However, the outputJournal function outputs an error under the journals argument passed to List.filter. The error is as follows: "Type mismatch. Expecting a 'Account list' but given a 'List Journal'. The type 'Account' does not match the type 'Journal'".
I am confused as to why this is, seeing as I am (or so I thought) clearly trying to filter a list of Journals. Is there a way I can override the type inference to do what I mean or otherwise make my intentions more clear to the compiler (renaming the account field in either record is an option, but I would like to avoid it)?
Much appreciated. Thank you.
Type inference in F# proceeds stricktly top to bottom, left to right.
As a result, when you do x.account the compiler guesses that x is an Account so you get the error message.
To fix this, you can do two things
1) Annotate the type of x
let filtered = List.filter (fun (x:Journal) -> x.account = account.account) journals
2) change the order with a pipe operator (thanks Fyodor)
let filtered = journals |> List.filter (fun x -> x.account = account.account)
Because of the way type inference works, (2) is more common

F# how to handle nullable types

I try to do some graphs in F#. As an input I have CSV file that has some values nullable (e.g. nullable int). I try to show chart with following code :
[for row in data.Rows -> row.A.Value, row.B.Value] |> Chart.Point
Where both A and B are nullable integers. I received following error
System.InvalidOperationException: Nullable object must have a value.
How I should handle nullable types. Should I write some Option type to handle it or there is some other good way how to solve it.
If you are using F# 4.0, then there is a built-in function Option.ofNullable. If no, then you can use the implementation in the other answer.
You can also use the same code to define an active pattern:
let (|Present|_|) (n:System.Nullable<_>) =
if n.HasValue then Some(n.Value)
else None
... this can be used inside a match construct and so you can write:
[ for row in data.Rows do
match row.A, row.B wih
| Present a, Present b -> yield a,b
| _ -> () ] |> Chart.Point
Where you are going wrong is: you are calling the Value property on something that might be null.
When you call Value you are effectively saying "It's okay, I have rigorously changed this value and it's definitely not null so it's perfectly safe to treat it as if it were a non-nullable value." Of course, in this case, that condition isn't met, hence the runtime exception.
In F#, you don't want to be working with Nullable<'T> types, you want to be working with Option<'T>, this is much safer and the compiler can check more effectively that you're not making a mistake.
You can convert from Nullable<'T> to Option<'T> for the list using
[for row in data.Rows -> Option.ofNullable (row.A), Option.ofNullable(row.B)]
Of course then you have to decide how you want to handle the None cases but it's much easier to do that once you've made your design explicitly tell you that you've got a value that may or may not be something.
I don't know what behaviour you want but, as an example, perhaps you want to only chart the cases where both values are valid?
You could zip two option values:
module Option =
let zip a b =
match (a,b) with
|Some sa, Some sb -> Some(sa, sb)
|_ -> None
You can then map back to plotable numbers, extracting the None cases using List.choose.
[for row in data.Rows -> Option.ofNullable (row.A), Option.ofNullable (row.B)]
|> List.choose (fun (a,b) -> Option.zip a b)
|> Chart.Point
Map the Nullable type to Option type and filter them out (with .filter or .choose) or transform the None's to a special value for missing values (e.g. 0, -1, NaN) depending on your data to make them working in the charting tool.
module Option =
let fromNullable (n: _ Nullable) =
if n.HasValue
then Some n.Value
else None

Can I Access Parameters of a Computation Expression?

Is it possible to create methods or stand-alone functions in a computation expression that can later be used by one of the canonical methods of a computation expression?
I want something like this:
type FormletBuilder(ctx : HttpContext) =
let get_int =
match Int32.TryParse (ctx.Request.["foo"]) with
| (true, n) -> Some n
| _ -> None
//similar definitions for get_date, get_non_empty_str, etc...
member x.Bind (read : 'a option, f : 'a -> option 'a) =
match read with
| Some x -> f(x)
| None -> None
member x.Return (obj) = Some obj
member x.Zero () = None
let person = formlet ctx {
let! id = get_int "id"
let! name = get_non_empty_str "fullname"
return Person(id, name)
}
But the compiler complains that get_int is not defined.
let bindings in class definitions are always private. You can define a member instead.
For an easy solution, you could do:
let formlet = FormletBuilder(ctx)
let person = formlet {
let! id = formlet.get_int "id"
...
}
I understand now that what you actually want is a maybe monad, and the workflow argument is there just to make use of some syntactic sugar? If so, there are a couple other things you can consider doing:
Go Haskell on it all the way and implement a MaybeReader monad, so that both the maybe and the reader parts of it are explicit in type,
Put the sugar away - I understand you don't actually need the context in any core builder members? If so, than maybe it had no business being an argument to the builder in the first place. Have a 'clean' maybe monad, move get_int etc. into a proper module and have them take HttpContext explicitly as an argument.
If you're using F# 3.0 or later, you can define get_int etc. as custom operations of the workflow, which should effectively give you the nice syntax you want to have. Here's a good post about it by Tomas Petricek.
Combine 2. and 3. - instead of a large number of custom operations, have one - ask - which will take an HttpContext -> 'a function and apply ctx to it. Effectively a bastardized version of reader. Then you can move your get_int etc. into a proper module.

what is use cases of F# explicit type parameters?

As I know, explicit type parameters in value definitions is a one way to overcome "value restriction" problem.
Is there another cases when I need to use them?
Upd: I mean "explicitly generic constructs", where type parameter is enclosed in angle brackets, i.e.
let f<'T> x = x
Polymorphic recursion is another case. That is, if you want to use a different generic instantiation within the function body, then you need to use explicit parameters on the definition:
// perfectly balanced tree
type 'a PerfectTree =
| Single of 'a
| Node of ('a*'a) PerfectTree
// need type parameters here
let rec fold<'a,'b> (f:'a -> 'b) (g:'b->'b->'b) : 'a PerfectTree -> 'b = function
| Single a -> f a
| Node t -> t |> fold (fun (a,b) -> g (f a) (f b)) g
let sum = fold id (+)
let ten = sum (Node(Node(Single((1,2),(3,4)))))
This would likely be rare, but when you want to prevent further generalization (ยง14.6.7):
Explicit type parameter definitions on value and member definitions can affect the process of type inference and generalization. In particular, a declaration that includes explicit generic parameters will not be generalized beyond those generic parameters. For example, consider this function:
let f<'T> (x : 'T) y = x
During type inference, this will result in a function of the following type, where '_b is a type inference variable that is yet to be resolved.
f<'T> : 'T -> '_b -> '_b
To permit generalization at these definitions, either remove the explicit generic parameters (if they can be inferred), or use the required number of parameters, as the following example shows:
let throw<'T,'U> (x:'T) (y:'U) = x
Of course, you could also accomplish this with type annotations.
Most obvious example: write a function to calculate the length of a string.
You have to write:
let f (a:string) = a.Length
and you need the annotation. Without the annotation, the compiler can't determine the type of a. Other similar examples exist - particularly when using libraries designed to be used from C#.
Dealing with updated answer:
The same problem applies - string becomes A<string> which has a method get that returns a string
let f (a:A<string>) = a.get().Length

Resources