Set.union F# trouble - f#

I have a Set<String*String>, and I'm trying to write a function that takes all the elements of that Set and return a Set<String>. My idea is to use Set.fold, and have an empty set accumulator and take the union of the two sets, but I'm running into problems. Here is the code:
type Chart = Set<Country*Country>;;
let countriesInChart (chart : Chart) =
Set.fold(fun (x,y) set -> Set.union [x;y] set ) chart []
But I get this error
Set.fold(fun (x,y) set -> Set.union [x;y] set ) chart [];;
--------------------------------^^^^^^^^^^^^^^^^^^^
error FS0001: This expression was expected to have type
'a * 'b
but here has type
Set<'c>

Look at your types and function signatures.
Set.fold takes a 'State -> 'T -> 'State as the folder function. 'State is the type that you're folding into and that will be the eventual return value, so in this case, you want it to be of type Set<Country>.
That means your lambda can't be right, because the first argument is a tuple. So we should probably switch the arguments of that lambda:
let countriesInChart (chart : Chart) =
Set.fold(fun set (x,y) -> Set.union [x;y] set ) chart []
Compiling that gives us
(96,39): error FS0001: This expression was expected to have type
Set<'a>
but here has type
'b list
(96,39) in this case is the Set.union function, and of course that is not used correctly, because it requires two sets, but we're passing it one set and a list. We can create a set from the list using Set.ofList:
let countriesInChart (chart : Chart) =
Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) chart []
Again, we're getting a different error, so we're probably making progress:
(96,80): error FS0001: This expression was expected to have type
Set<(Country * Country) * (Country * Country)>
but here has type
'a list
(96,80) is the empty list at the end of the line - and of course, that's wrong, because the third argument to Set.fold needs to be Set<'T>. The set replacement for an empty list would be Set.empty, so let's go with that:
let countriesInChart (chart : Chart) =
Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) chart Set.empty
It compiles! But as you found, it returns Set<Country * Country> instead of just Set<Country>.
Cases like this are when type inference makes it a little harder to see what's going on, so we should go ahead and add type annotations where we know exactly what the types need to be. The most obvious place is the return type of the function:
let countriesInChart (chart : Chart) : Set<Country> =
Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) chart Set.empty
Now the error is:
(96,74): error FS0001: Type mismatch. Expecting a
Set<Country>
but given a
Chart
The type 'Country' does not match the type 'Country * Country'
That error is for the second argument of Set.fold, and the reason is that once again, the arguments are in the wrong order. The signature of Set.fold is ('State -> 'T -> 'State) -> 'State -> Set<'T> -> 'State. If we look at what we already have, 'State in this case is Set<Country>, and 'T is Country * Country. That means Set.empty needs to be the second and chart the last argument, and so we arrive at
let countriesInChart (chart : Chart) =
Set.fold(fun set (x,y) -> [x; y] |> Set.ofList |> Set.union set) Set.empty chart
The most important rule of functional programming is this: Let the types guide you! ;-)

Try this one:
let f (chart: Chart) =
Set.fold (fun (x:Set<string>) (a,b) -> x |> Set.add a |> Set.add b) Set.empty chart
I'm not sure if the type annotation is necessary but it does force the output to be a Set<string>.

Related

Trying to compare length of each sub-list (learning about lambda and list modules)

I'm trying to make a function that checks a lists sublists to see if they have equal length and returns a bool value.
[ [1;2;3]; [4;5;6] ] (return true)
[ [1;2;3]; [4;5] ] (return false)
I'm trying to learn about lambda's and list modules.
So far I have:
let isTable (lst : 'a list list) : bool =
List.forall (fun x -> x.Length = 2) ([ [1;2;3]; [4;5;6] ])
It says x.Length is wrong somehow.
Can someone explain what I am doing wrong?
The problem with your code is that the F# type inference does not know what is type of x when checking the lambda function and so it cannot check whether the object will have a member Length. The type inference checks your program from left to right and so it only figures out that x will be a list when it gets to the argument [ [1;2;3]; [4;5;6] ] later in your code.
There is a couple of ways to fix this. You can use List.length which is a function and not an instance member, so the inference can check that:
let isTable (lst : 'a list list) : bool =
List.forall (fun x -> List.length x = 2) [ [1;2;3]; [4;5;6] ]
A nicer alternative is to use the |> operator which passes the thing on the left to the function on the right, so writing x |> f is the same as calling f x. This puts the input to the left, so the inference will work:
let isTable (lst : 'a list list) : bool =
[ [1;2;3]; [4;5;6] ] |> List.forall (fun x -> x.Length x = 2)
Finally, you could also add a type annotation:
let isTable (lst : 'a list list) : bool =
List.forall (fun (x:_ list) -> x.Length = 2) [ [1;2;3]; [4;5;6] ]
Out of these three, I think the most idiomatic solution is to use |>, but List.length is also common.
Try this code:
let isTable (lst: 'a list list) =
match lst with
| [] | [[]] -> false
| []::t -> false
| [_] -> true
| h::t -> t |> List.forall(fun l -> l.Length = h.Length)
The issue you are having is that the type inference system of F# does not firmly recognize x as being a list at the point where you want to do x.Length. That may seem strange because if you use Intellisense (for instance by hovering over x) it will tell you that it is a list, yet the compiler complains.
The reason for that is that F#'s type inference does not work as well when working with Object Oriented (OO) dot . notation, it does much better when using functional dot . notation. To differentiate between the two, the convention in F# (and .Net) is that class members (methods and properties) start with a capital letter (also known as Pascal Case) hence x.Length. On the other hand, functional style code (like functions in a module and/or record members) start with a lower case (known as Camel Case) like List.length.
Notice the difference between the 2 styles:
OO, invoke a method: x.Length
Functional, call a function: List.length x
If you want to use the OO style, typically the solution is to add a type annotation, which you can do in several ways:
fun (x:_ list) -> x.Length = 2
fun x -> (x:_ list).Length = 2
In general, it is better practice to use the functional style. But, you do not always have a choice. For instance there are many String methods that do not have a functional equivalent:
fun (s:string) -> s.StartsWith "Hello"
I also would like to point out that your code as stated does not really do what you want. It returns true only if all lists are of length 2, not if all of them are the same length.
kagetoki's solution works and also demonstrates the use of pattern matching for lists.
Here is a simplified version:
let isTable lst =
match lst with
| h::t -> t |> List.forall(fun (l:_ list) -> l.Length = h.Length)
| _ -> true
Notice that by stating that l is a list, it already knows that h is also a list.
Finally, just for fun, a super compact (but obscure) version :
let isTable =
function
| h::t -> t |> List.forall (List.length >> (=) h.Length)
| _ -> true

F# deedle transform Series<string, obj> to Series<string, float>?

If I get a row of Frame by using the .Rows.[rowIndex] operation, Deedle will return me an Object Series. Sometimes I know this only contains float. How do i convert all the obj into float series in on shot?
In Deedle series are generic, so ideally it should be possible to get a float series right away. But as the reasons why you get a series of Objects is not clear, you can still convert the values to floats by mapping an appropriate type casting function:
#load #"..\packages\Deedle.1.2.4\Deedle.fsx"
open Deedle
open System
// Let's prepare a sample series
let keys = ["1";"2";"3"]
let values = [1.1 :> Object;1.2 :> Object;1.3 :> Object]
let series = Series(keys, values)
// Now apply the map taking the Series<string,System.Object> series to Series<string,float>
series |> Series.map (fun _ v -> v :?> float)
// as #Foggy Finder pointed out, there is a convenience function to only map values
series |> Series.mapValues (fun v -> v :?> float)
// Alternatively, use the tryMap function that takes the Series<int,Object> series
// to Series<int,TryValue<float>>
series |> Series.tryMap (fun _ v -> v :?> float)
The type of the Series.map function is (('a -> 'b -> 'c) -> Series<'a,'b> -> Series<'a,'c>) when 'a : equality. This means that the first argument of the mapping function is the key which we ignore using the underscore as it is not needed to make the type cast. As Foggy Finder pointed out, there is a convenience function Series.mapValues that hides the keys.

Trouble with Set.forall F#

I'm having trouble trying to compare an element to all elements of a set. I want to write a boolean function that returns true if an element is not a neighbour and false if an element is a neighbour. We want to colour the chart
so that two countries that share a border are not given the same colour. I will explain it with code
type Country = string;;
type Chart = Set<Country*Country>;;
type Colour = Set<Country>;;
type Colouring = Set<Colour>;;
(* This is how you tell that two countries are neighbours. It requires a chart.*)
let areNeighbours ct1 ct2 chart =
Set.contains (ct1,ct2) chart || Set.contains (ct2,ct1) chart;;
(* val areNeighbours :
ct1:'a -> ct2:'a -> chart:Set<'a * 'a> -> bool when 'a : comparison
*)
I'm having trouble with the canBeExtBy function. If this is my chart and my col:
val myWorld : Chart =
set
[("Andorra", "Benin"); ("Andorra", "Canada"); ("Andorra", "Denmark");
("Benin", "Canada"); ("Benin", "Denmark"); ("Canada", "Denmark");
("Estonia", "Canada"); ("Estonia", "Denmark"); ("Estonia", "Finland");
...]
col = set
["Canada"]
then my function should return false if I call
canBeExtBy col "Denmark" myWorld;;
Here is my code, I get an error which is listed at the bottom.
(* The colour col can be extended by the country ct when they are no neighbours
according to chart.*)
val canBeExtBy :
col:Set<'a> -> ct:'a -> chart:Set<'a * 'a> -> bool when 'a : comparison
*)
Error:
Set.forall(fun x -> areNeighbours x ct) col;;
----------------------^^^^^^^^^^^^^^^^^^
This expression was expected to have type
bool
but here has type
Set<'a * 'a> -> bool
Listen to your types.
This expression was expected to have type
bool
but here has type
Set<'a * 'a> -> bool
Instead of a boolean value, there is a function of type Set<'a * 'b> -> bool. That is a sign for a partially applied function that's missing its last argument of type Set<'a * 'b>. If you look at your areNeighbours function, you can see that it takes three arguments, two of type Country, and one of type Chart, but in canBeExtBy, you're only passing it two Country values, but not the Chart.
To make it compile, canBeExtBy needs to look like this:
let canBeExtBy col ct chart =
Set.forall(fun x -> areNeighbours x ct chart |> not) col

Trouble declaring union of C# classes in F#

I'm using the Forecast.io C# weather library, which provides several classes for weather forecasts over different time periods (e.g., hourly, daily, "right now"), which all contain similar data.
I'm trying to write functions that will accept any of these classes, but I'm getting some compile errors (below) that I don't understand:
For the FS0001 errors, Why is the getTemp function not satisfied with an object that matches the Forecast union type? Why does it expect a different parameter type in each case?
For the FS0019 error, what constructor is it referring to? Why is it expecting me to supply an argument to this constructor?
Here is some example code:
open ForecastIO
type Forecast =
| Currently of ForecastIO.Currently
| HourForecast of ForecastIO.HourForecast
let getTemp forecast =
match forecast with
| Currently -> forecast.temperature
| HourForecast -> forecast.temperature
|> float
let forecastForDate date =
let request = new ForecastIORequest("api_key", 35.780556f, -78.638889f, date, Unit.us);
request.Get ()
let test () =
let baseDate = System.DateTime.Parse "2014-06-12 22:00:00"
let forecast = forecastForDate baseDate
forecast
|> (fun r -> r.currently)
|> getTemp
|> printfn "%f"
forecast
|> (fun r -> r.hourly.data.[0])
|> getTemp
|> printfn "%f"
test ()
And here is my compiler output:
/tmp/forecast.io/test2.fs(9,15): error FS0019: This constructor is applied to 0 argument(s) but expects 1
/tmp/forecast.io/test2.fs(23,12): error FS0001: Type mismatch. Expecting a
Currently -> 'a
but given a
Forecast -> float
The type 'Currently' does not match the type 'Forecast'
/tmp/forecast.io/test2.fs(28,12): error FS0001: Type mismatch. Expecting a
HourForecast -> 'a
but given a
Forecast -> float
The type 'HourForecast' does not match the type 'Forecast'
There are a few different issues. One is as #mydogisbox mentions - if you DU cases have fields, you are required to consider them in your pattern matching, either ignoring them with _ or capturing into some identifier.
The main issue, though, is that you are not creating an instance of your DU anywhere. The .currently property of your forecast object might be of type ForecastIO.Currently, and .hourly.data.[0] of type ForecastIO.HourForecast, but that doesn't mean you can take those values and treat them like cases from your Forecast DU. You need to explicitly construct the case you want:
forecast
|> (fun r -> Currently(r.currently))
|> getTemp
|> printfn "%f"
forecast
|> (fun r -> HourForecast(r.hourly.data.[0]))
|> getTemp
|> printfn "%f"
If you don't want to define a DU and instead really just want to pattern match against the type of the input, you can do something like what #Jan suggests, and not even have to define a DU:
let getTemp forecast =
match forecast with
| :? ForecastIO.Currently as c -> c.temperature
| :? ForecastIO.HourForecast as h -> h.temperature
|> float
When decomposing DUs you need to specify the name of the constructor parameters (i.e. the parameters needed to construct that DU case). In this case you don't want to use them so you can just blank them out like this:
let getTemp forecast =
match forecast with
| Currently _ -> forecast.temperature
| HourForecast _ -> forecast.temperature
|> float
Works the following better?
let getTemp forecast =
match forecast with
| :? Currently as c -> c.temperature
| :? HourForecast as h -> h.temperature
|> float

Define sum of square without defining parameter

I want to define sumOfSquares without explicity using parameter, relying instead on functional composition
Here's my code below
let sumOfSquares = Seq.map (fun n -> n * n) >> Seq.sum
However, I got the following error
stdin(80,5): error FS0030: Value restriction. The value 'sumOfSquares'
has been inferred to have generic type
val sumOfSquares : ('_a -> int) when '_a :> seq<int>
Either make the arguments to 'sumOfSquares' explicit or, if you do not intend for
it to be generic, add a type annotation.
One way to resolve it is by using parameters
let sumOfSquares nums = nums |> Seq.map (fun n -> n * n) |> Seq.sum
and this will work. However, I want to see if I can define sum of squares by using composition alone
Update
Here's a nice article describing the issue I've encountered: Value Restriction.
Make a type annotation:
let sumOfSquares : seq<int> -> int =
Seq.map (fun n -> n * n) >> Seq.sum
So lets see what happens when the type inference tries to work here. First you have
Seq.map (fun n -> n * n) >> Seq.sum
Now as Seq allows for anything that implements Seq, we can input int list int[] or many others.
As a result, you get this as the type
val sumOfSquares : ('_a -> int) when '_a :> seq<int>
Now the problem is that sumofSquares is a value (which is a function). Unfortunately, you can't have a generic value in a top level binding. You can though have a generic function, if you make the arguments explicit.
As a result, one alternative to a type annotation is to make the argument explicit like so
let sumOfSquares s= s |> Seq.map (fun n -> n * n) |> Seq.sum
And this works
Searching SO for "value restriction errors" should give some more examples of this problem.

Resources