I've constructed a mutual-recursive type, consisting of more primitive types also defined like follows:
type Title = Title of string;;
type Value = Value of int;;
type Subcol = Collection list
and Collection =
| Col of Title * Value * Subcol
;;
The subcol may or may not be the empty list, but if it isn't, I'd like to sum both the value of the given collection as well as recursive call on Subcol and the Value defs it might contain. To do this I've constructed the following function:
let rec colList = function
| [] -> 0
| _::v::s -> (colList s) + sumVal v
and sumVal = function
| Value v -> v
and col = function
| Col(_,v,[]) -> (sumVal v)
| Col(_,v,s) -> (sumVal v) + (colList s)
;;
I expect the function call colList s in
Col(_,i,s) -> (sumVal i) + (colList s)
to produce an int from a Subcol type, however I get the following error:
error FS0001: Type mismatch. Expecting a
Value list but given a
Subcol The type 'Value' does not match the type 'Collection'
I want the colList to accept Subcols, not Value lists.
Any help is appreciated, thank you.
Related
I am trying to access the fst element of a tuple. Normally I use fst (tuple), but this situation is a little different.
let getCard (pl : player) : (card * player) option =
let plDeck = pl
match plDeck with
| c1::re -> Some (c1,(re))
| [] -> None
This is my f# code. the player type is a list of ints, and the output is tuple with the first int of the player list, and the player list minus the first int.
It's an assignment from my computer science class, so it is required that I use the option type.
I am trying to access the fst element of the tuple in another function by writing
let gc = fst (getCard [1,2,3])
but it seems like I can't do it this way, since I am getting the warning:
This expression was expected to have type
''a * 'b' but here has type
'(card * player) option'
How do I work around this?
The compiler is telling you that you're trying to access an option of tuple card * player while the function fst expects a tuple of card * player.
You could pattern match on your getCard function and extract the card.
let result =
match getCard [1..5] with
| Some card -> fst(card)
| None -> -1
You could also use pattern matching to extract the first part of your tuple.
let result =
match getCard [1..5] with
| Some (card, _) -> card
| None -> -1
As suggested by #Guran you shouldn't return magic numbers
let result =
match getCard [1..5] with
| Some (card, _) -> Some card
| None -> None
When I run the code below I get an error. I am using Map.TryFind and its not working. In console, I get a red line under familyinc.TryFind(tract) and the error below.
let data =
seq { for (state,work) in statecsv do
let (family,income) = familyinc.TryFind(state)
let fam =
match fam with
| Some x -> x
| None -> "Not a Record"
let inc =
match inc with
| Some x -> x
| None -> "Not an income"
yield (state,work,inc,fam)
}
The ERROR:
error FS0001: This expression was expected to have type
''a * 'b'
but here has type
'(string * decimal) option'
Answer to the edited question: The problem is the same as in the previous one, you are pattern matching on a tuple while you are binding an option. You should do something like this instead:
// Bind the whole option
let result = familyinc.TryFind(state)
// Pattern match on it
match result with
| Some (family , income) -> yield (state,work,family,income)
| None -> yield (state,work,"Not a Record","Not an Income")
Of course you could also do match familyinc.TryFind(tract) with, there's no need to bind to variable here.
The issue is you are pattern matching on the result of Map.TryFind() as if it would return a tuple but it actually returns an option as it may fail to find they key you are looking for.
In all FP languages understanding option types and pattern matching is essential. In fact both of these features make FP a superior alternative to OO languages. Using option types you can avoid getting null exceptions, using pattern matching you can deconstruct values. In this case you can filter out non-existing keys, and convert the option result into normal values:
//create test dictionary
let map1 = [("a",1); ("b",2);("c",3)] |> Map.ofList
//list of keys, "d" doesn't exist in the dictionary/map
let keys = ["a";"b";"d"]
keys
|> List.map (fun x -> map1.[x])
//System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
keys
|> List.map (fun x -> map1.TryFind(x))
//You get back a string option list, with the last element missing as the key "d" doesn't exist
//val it : int option list = [Some 1; Some 2; None]
//Method A: filter out the none existing items
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.choose id //choose will get rid of the Nones and return the actual value, not the option. id is the identity function.
//Method B: replace the None with some default value, and also get rid of the option
//Let's say you replace each non existing value with 999
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.map (Option.defaultValue 999)
//val it : int list = [1; 2; 999]
//In general if necessary you can always pattern match
let myOption1 = Some "A"
let myOption2 = None
match myOption1 with
| Some x -> x //try matching whatever is in myOption1 and returns the x portion of Some x, in this case "A"
| None -> "No value"
//val it : string = "A"
match myOption2 with
| Some x -> x
| None -> "No value" //since the value of myOption2 is None, Some x won't match, None will match, and return "No value"
//val it : string = "No value"
Given the following set of types representing a store:
type Article = string
type Amount = int
type Price = int
type Desc = Amount*Price
type Stock = (Article*Desc) list
type Order = Article * Amount
type Status<'a> = Result of 'a | Error of string
I want to make a function which takes an Order and a Stock and returns a Status<Price * Stock>. The value of the defined function below get (a,k) st is Result (p,st') where p is the price of k pieces of a and st' is the new stock obtained from st by removal of k pieces of a.
Example:
let rec get (a,k) st =
match st with
| (a',(n',p'))::rest when a'=a -> Result (p'*k,(a',(n'-k,p'))::rest)
| (a',(n',p'))::rest ->
match get (a,k) rest with
| Result (price,stock) -> Result (price,(a',(n',p'))::stock)
| Error e -> Error e
get ("a2", 10) st
val it : int * (string * (int * int)) list =
Result (200, [("a1", (100, 10)); ("a2", (40, 20)); ("a3", (25, 40))])
Now, how would I go about doing this if I took an Order list?
Such as get [("a2",10);("a1",10)] st would return Result (300, [("a1", (90, 10)); ("a2", (40, 20)); ("a3", (25, 40))])
type Article = string
type Amount = int
type Price = int
type Desc = Amount * Price
type Stock = (Article * Desc) list
type Order = Article * Amount
type Status<'a> = Result of 'a | Error of string
First, since you ask for an implementation of the function get, let’s rename the existing function get into getArticle.
let rec getArticle (a, k) st =
match st with
| (a', (n', p')) :: rest when a' = a -> Result (p' * k, (a', (n' - k, p')) :: rest)
| (a', (n', p')) :: rest ->
match getArticle (a, k) rest with
| Result (price, stock) -> Result (price, (a', (n', p')) :: stock)
| Error e -> Error e
| [] -> Error "Article not in stock"
I also added an extra case to get rid of the “Incomplete pattern matches” warning.
The answer to your question is List.fold.
The first argument of List.fold is a folder function of type 'State -> 'ElementType -> 'State. In this question, 'ElementType is Order.
getArticle does pretty much what the folder function is supposed to do: compute the next state, when traversing one element —in this question: one order— in the list. But not quite:
getArticle takes as input state a Stock but returns as output state a Status<Price * Stock>, in which the extra Price is the total price of the retrieved articles (so far). List.fold expects the input and output state of the folder function to be the same type.
getArticle takes as first argument an element from the list —which in this question has type Order—, and as second argument the input state. List.fold expects a folder function that takes these two arguments swapped.
So, let’s constuct a folder function, in which the total price of the retrieved articles so far is accumulated (added):
let folder status order =
match status with
| Result (totalPriceSoFar, stock) ->
match getArticle order stock with
| Result (price, st) -> Result (totalPriceSoFar + price, st)
| Error e -> Error e
| Error f -> Error f
We’re practically done now.
The second argument of List.fold is the inital state — in this question: a Result with the initial stock and the total price so far initialised to 0.
The third argument of List.fold is the list over which to iterate — in this question: the list of orders.
let get orders initialStock =
let initialStatus = Result (0, initialStock)
List.fold folder initialStatus orders
let initialStock = [("a1", (100, 10)); ("a2", (50, 20)); ("a3", (25, 40))]
get [("a2", 10); ("a1", 10)] initialStock
Closing remark
You chose to define the type Stock as (Article * Desc) list. Given that you use this list basically as a look-up map in which an article can’t have 2 prices or 2 amounts, why not choose Map<Article, Desc>?
given the following type
type Foo = { foo: string; bar: int };;
and the following code quotation
<#fun v x -> { x with foo = v; bar = 99 } #>;;
this will result in
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, v, Value (99))))
Which is expected. Also the following code quotation
<#fun v x -> { x with bar = v;foo = "foo" } #>;;
yields the expected result.
val it : Quotations.Expr<(int -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, Value ("foo"), v)))
However this (changing the order and assigning the value to the second field)
<#fun v x -> { x with bar = 66;foo = v } #>;;
yields
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, Let (bar, Value (66), NewRecord (Foo, v, bar))))
a let. But there is no let in the code. Why is this?
Quotations only guarantee that they'll generate expressions with the correct behaviour, not any specific shape.
For example the quotation <## 1 = 2 || 2 = 3 ##> will generate an expression comprising of an if statement (i.e. if 1 = 2 then true else 2 = 3).
Normalising the resulting expressions is a pretty deep rabbit hole, but you can see some basic normalisers here: https://github.com/mavnn/Algebra.Boolean/blob/master/Algebra.Boolean/Transforms.fs
Specifically, check unbind at the end of the file.
let unbind quote =
let rec findLet q =
match q with
| Let (var, value, body) ->
findLet (replaceVar var.Name value body)
| ShapeLambda (v, e) ->
Expr.Lambda(v, findLet e)
| ShapeVar v ->
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map findLet)
and replaceVar name value q =
match q with
| Let (v, e, e') ->
if v.Name = name then
findLet (Expr.Let(v, e, e'))
else
Expr.Let(v, replaceVar name value e, replaceVar name value e')
| ShapeLambda (v, e) ->
Expr.Lambda(v, replaceVar name value e)
| ShapeVar v ->
if v.Name = name then
value
else
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map (replaceVar name value))
findLet quote
As to why these specific expressions are different? No idea, I'm afraid!
I believe what you are seeing here is a particular case of de-sugaring of the with syntax on records. I think what is happening here it is using the v to capture the value to ensure that the expressions are evaluated in the correct order of the fields. So in this case the let binding is introduce as the passed in parameter is the 2nd value being utilised.
This is from the F# language spec.
Primitive record constructions are an elaborated form in which the
fields appear in the same order as in the record type definition.
Record expressions themselves elaborate to a form that may introduce
local value definitions to ensure that expressions are evaluated in
the same order that the field definitions appear in the original
expression
I have a discriminated union like this:
type A = |B | C of int*A
I have to pattern match like this (the parenthesis appear to be needed):
match x with
| B -> printfn "B"
| C (i,a) -> printfn "%A, %A" i a
Is there a way to instead match like this with something like an active pattern:
match x with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a
And if not how come F# is designed such that this matching with curried arguments doesn't work and it instead forces you to use a tuple?
Edit: This was inspired by the F# list in which you can use h::t without any tupling or anything like that. And the source code is like:
type List<'T> =
| ([]) : 'T list
| (::) : Head: 'T * Tail: 'T list -> 'T list
I think examining the definitions of a curried function and an active pattern will make this clear for you.
Curried function:
A function which takes multiple parameters but which allows you to pass them in one at a time in order to return a function which does the same thing but takes one fewer parameters. Example:
let add a b = a + b
//val add : a:int -> b:int -> int
let add5 = add 5
//val add5 : (int -> int)
Active Pattern:
A way of applying pattern matching where the matching can be done using parsing or other complex logic. Takes one parameter and returns the result of the parsing. So input -> single return parameter.
//Example taken from https://fsharpforfunandprofit.com/posts/convenience-active-patterns/
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| (true,int) -> Some(int)
| _ -> None
val ( |Int|_| ) : str:string -> int option
Since the whole point of currying a function is to be able to partially apply the function, the concept simply makes no sense when applied to the result of an active pattern.
Put another way, the result of an active pattern can't be "curried" because you can only curry functions and the result of an active pattern is data which is not a function. In your example, 'C (i,a)' is defining the return type of the Active Pattern case, not a function call.
You cannot have whitespace as delimiter between bound patterns, because neither union cases nor active patterns support this. Syntax as per the F# spec:
6.9.8 Evaluating Union Case
Case(e1,…,en)
7.2.3 Active Patterns
(|CaseName|) arg1 ... argn inp
(|CaseName|_|) arg1 ... argn inp
So it's necessarily one tupled argument for a union case; and n+1 arguments for the banana function, of which n arguments are parameters. Only the last argument binds to the pattern. Consider:
type X = B | C
let (|C|) a b = C (a, b)
let i = 42
match C with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a // prints 42, (42, C)
The case C in your discriminated union has a value of a tuple type (int * A).
The (i,a) part of your pattern matching isn't a parameter, it's matching the i to the int part and the a to the A part.
You could equally match with C x and x would hold a tuple of (int * A).