Expected bool but has different type - f#

In the following method, I get the following error: error FS0001: This expression was expected to have type bool but here has type Outcome list * ProbTree -> bool when trying to call isSample in the if expression. I have no clue why I get the message.
isSample(os, t) is currently of type 'a * 'b -> Outcome list * ProbTree -> bool. Any ideas? What I don't understand is why it expects type bool all of a sudden.
let rec isSample(os, t) = function
| ([], Branch(_, p, b1, b2)) -> false
| (os, Branch(_, p, b1, b2)) when List.length os = 1 -> true
| (h::t, Branch(_, p, b1, b2)) ->
if h = S then isSample(t, b1) else isSample(t, b2) //This is where I get the error
| _ -> false
type Outcome = | S | F
type Sample = Outcome list
type ProbTree = | Branch of string * float * ProbTree * ProbTree
| Leaf of string

Related

Generic pattern matching in function argument

Let say I have DU of three types and a function which accepts this DU as a parameter:
type A = decimal<p>
type B = decimal<p>
type C = decimal<p>
type ABC = A of A | B of B | C of C
let myfunc (val: ABC) =
match val with
| A v -> ...
| B v -> ...
| C v -> ...
Is there a better way to define a function which accepts DU of only A and B without defining new type explicity?
This is a working example:
type AB = A2 of A | B2 of B
let myfunc2 (val: AB) =
match val with
| A2 v -> ...
| B2 v -> ...
This is how I would like it to be:
let myfunc2 (val: A|B) =
match val with
| A v -> ...
| B v -> ...
The language feature you're asking for is open variants, which exists in OCaml, but not in F#. For instance,
type ABC = A of int | B of int | C of int
type AB = A of int | B of int
let myfunc (x: AB) = ...
is legal in OCaml. This can also be achieved with type-erased DUs (vote for it here!).
DU cases in F# are not actual types, but the base type (ABC) with a tag denoting which union case it is. And since there are no types which exist separately, it follows that they cannot be used as a type constraint.
You can however try and work around this with Choice. The idea is to build single case DUs and then combine them with Choice<T1, T2...>.
type A = A of int
type B = B of int
type C = C of int
type ABC = Choice<A, B, C>
type AB = Choice<A, B>
let matchAb (x: AB) =
match x with
| Choice1Of2 (A a) -> a
| Choice2Of2 (B b) -> b

What is wrong in F# code?

In F# I am trying to get last element of give list. I wrote below code
let rec findLast t =
match t with
| hd :: [] -> hd
| hd :: tl -> findLast tl
| _ -> -1
printfn "%A" (findLast [1,2,3,4,5])
But when I tried to execute it in F# Interactive it complain as below
error FS0001: This expression was expected to have type
int but here has type
'a * 'b * 'c * 'd * 'e
I just want to know what is wrong in above code. I know there are different smart and elegant ways to get last element from list in F#. But I am interested to know what is wrong in above code ?
1,2,3,4,5 is a tuple. 'a * 'b * 'c * 'd * 'e is a tuple definition. Create a list with semicolons [1;2;3;4;5]. [1,2,3,4,5] is a list of tuples with one item which is a quintuple.
let rec findLast t =
match t with
| hd :: [] -> hd
| hd :: tl -> findLast tl
| _ -> -1
printfn "%A" (findLast [1;2;3;4;5])
Try this one:
let rec lastElem = function
| [] -> None
| [x] -> Some x
| x::xs -> lastElem xs
You can try it in the REPL:
> lastElem [1;2;3];;
val it : int option = Some 3
> lastElem ["a";"b";"c"];;
val it : string option = Some "c"
As #Phillip-Scott-Givens pointed out, you've likely made a totally common (especially for C#'ers), error and used a comma to separate a list instead of a semi-colon.
This results in a tuple list [(1, 2, 3, 4, 5)] and not an integer list [1;2;3;4;5]. Getting unexpected asterisks in your type definitions is a symptom of this :)
That said, here a few different functions that get the last value from your tuple, list, and tuple list (ref: https://stackoverflow.com/a/1175123/5470873):
// Data:
let tuples = [ (1,2,3,4,5); ] // = [1,2,3,4,5]
let firstListElement = tuples.[0]
// Access:
let rec lastItemInList = function
| hd :: [] -> hd
| hd :: tl -> lastItemInList tl
| _ -> failwith "Empty list."
let lastValueOfFirstItem = function
| (_, _, _, _, last) :: _ -> last
| _ -> -1
let lastValueOfTuple = function _, _, _, _, last -> last
// same as: let lastValueOfTuple myTuple =
// match myTuple with
// | (_, _, _, _, last) -> last
// Examples:
tuples |> lastItemInList // val it : int * int * int * int * int = (1, 2, 3, 4, 5)
tuples |> lastValueOfFirstItem // val it : int = 5
tuples |> List.map lastValueOfTuple // val it : int list = [5]
firstListElement |> lastValueOfTuple // val it : int = 5

How does recursion work for active patterns in F#?

I have the following function for parsing an integer:
let rec digits = function
| head::tail when System.Char.IsDigit(head) ->
let result = digits tail
(head::(fst result), snd result)
| rest -> ([], rest)
If I change this function to be an active recognizer, it no longer compiles.
let rec (|Digits|) = function
| head::tail when System.Char.IsDigit(head) ->
let result = Digits tail
(head::(fst result), snd result)
// ^^^^^^ ^^^^^^ see error*
| rest -> ([], rest)
*error FS0001: This expression was expected to have type char list * 'a but here has type
char list
let rec (|Digits|) = function
| head::(Digits (a, b)) when System.Char.IsDigit(head) -> (head::a, b)
| rest -> ([], rest)
NOTE:
if you want to use active pattern as a function you still can do it:
let rec (|Digits|) = function
| head::tail when System.Char.IsDigit(head) ->
let a, b = (|Digits|) tail
(head::a, b)
| rest -> ([], rest)

Simplifying nested pattern matching F#

I am writing a simple expressions parser in F# and for each operator I want only to support a certain number of operands (e.g. two for Modulo, three for If). Here is what I have:
type Operator =
| Modulo
| Equals
| If
let processOperator operands operator =
match operator with
| Modulo ->
match operands with
| [ a:string; b:string ] -> (Convert.ToInt32(a) % Convert.ToInt32(b)).ToString()
| _ -> failwith "wrong number of operands"
| Equals ->
match operands with
| [ a; b ] -> (a = b).ToString()
| _ -> failwith "wrong operands"
| If ->
match operands with
| [ a; b; c ] -> (if Convert.ToBoolean(a) then b else c).ToString()
| _ -> failwith "wrong operands"
I would like to get rid of or simplify the inner list matches. What is the best way to accomplish this? Should I use multiple guards ?
open System
type Operator =
| Modulo
| Equals
| If
let processOperator operands operator =
match (operator, operands) with
| Modulo, [a: string; b] -> string ((int a) % (int b))
| Equals, [a; b] -> string (a = b)
| If, [a; b; c] -> if Convert.ToBoolean(a) then b else c
| _ -> failwith "wrong number of operands"
But I would suggest to move this logic of the operands to the parser, this way you get a clean operator expression, which is more idiomatic and straight forward to process, at the end you'll have something like this:
open System
type Operator =
| Modulo of int * int
| Equals of int * int
| If of bool * string * string
let processOperator = function
| Modulo (a, b) -> string (a % b)
| Equals (a, b) -> string (a = b)
| If (a, b, c) -> if a then b else c
Fold in the operands matching:
let processOperator operands operator =
match operator, operands with
| Modulo, [a; b] -> (Convert.ToInt32(a) % Convert.ToInt32(b)).ToString()
| Equals, [a; b] -> (a = b).ToString()
| If, [ a; b; c ] -> (if Convert.ToBoolean(a) then b else c).ToString()
| _ -> failwith "wrong number of operands"
Better yet, if you can, change the datatype to the following.
type Operator =
| Modulo of string * string
| Equals of string * string
| If of string * string * string
Then in the match, you can no longer fail.

Strange (?) type mismatch error in this function

Can someone explain why compiler is giving me this error
Type mismatch. Expecting a
'a [] -> string
but given a
'a [] -> 'a []
The type 'string' does not match the type ''a []'
on this code snippet:
let rotate s: string =
[|for c in s -> c|]
|> Array.permute (function | 0 -> (s.Length-1) | i -> i-1)
while the one below compiles just fine:
let s = "string"
[|for c in s -> c|]
|> Array.permute (function | 0 -> (s.Length-1) | i -> i-1)
Your first snippet defines function rotate with return type of string.
Try to change it to:
let rotate (s: string) =
[|for c in s -> c|]
|> Array.permute (function | 0 -> (s.Length-1) | i -> i-1)
In this form you define a function with one string argument (I suppose that's what you wanted) and inferred return type.

Resources