printing truth table confusion - f#

I'm trying to understand the code from the book Programming F# 3.0 by Chris Smith.
The following code prints the truth table for the given function.
> // Print the truth table for the given function
let printTruthTable f =
printfn " |true | false |"
printfn " +-------+-------+"
printfn " true | %5b | %5b |" (f true true) (f true false)
printfn " false | %5b | %5b |" (f false true) (f false false)
printfn " +-------+-------+"
printfn ""
();;
val printTruthTable : (bool -> bool -> bool) -> unit
A sample output..
> printTruthTable (&&);;
|true | false |
+-------+-------+
true | true | false |
false | false | false |
+-------+-------+
val it : unit = ()
However, I do not understand the following line
printfn " true | %5b | %5b |" (f true true) (f true false)
In my mind it seems it should resolve to (which doesn't make sense)
printfn " true | %5b | %5b |" (&& true true) (&& true false)
But this does does not execute.
Could someone explain this please?

It is resolved to
printfn " true | %5b | %5b |" ((&&) true true) ((&&) true false)
Which prints
true | true | false |

Related

How to properly write an if condition inside assert?

f({bool b, String s}) {
assert(b ? s != null : true);
}
Is there any better way to write the above assert based on the condition?
You can always rewrite a boolean conditional expression (?-:) where one branch is a boolean literal, into a combination of ||, && and !.
| Bad conditional | Good and/or |
|-----------------|-------------|
| b ? true : v | b || v |
| b ? false : v | !b && v |
| b ? v : true | !b || v |
| b ? v : false | b && v |
So, in your case: assert(!b || s != null);

Equality checking in F#

I'm trying to write a function where I have a helper function, 'a -> bool. My problem is, when I'm trying to use the return value from this helper function, I get the error (because it is a function?)
The type 'a -> bool' does not support the 'equality' constraint,
Is there a way to get it to pre-evaluate the function so that I can use the return value?
Example:
let primelist n =
let rec prim n = function
| [] -> true
| x::xs when n % x = 0 -> false
| x::xs -> prim n xs
let rec help n list = function
| n when (prim n = true) -> List.rev (n::list)
| n -> List.rev list
| i when (prim i = true) -> help n (i::list) (i+1)
| i -> help n list (i+1)
help [2] n
Something like this would do the trick:
let primelist n =
let rec prim n = function
| [] -> true
| x::xs when n % x = 0 -> false
| x::xs -> prim n xs
let rec help n list arg =
let prime n = prim n list
match arg with
| n when (prime n = true) -> List.rev (n::list)
| n -> List.rev list
| i when (prime i = true) -> help n (i::list) (i+1)
| i -> help n list (i+1)
help [2] n
Here I have used currying to create a new function.

F# remove trailing space

I have this method that takes in a list and turns it into a bytecode string. It works the way I expect; however, I get one trailing space that I do not want. Question: how do I get rid of this last trailing 0?
Input: byteCode [SC 10; SC 2; SAdd; SC 32; SC 4; SC 5; SAdd; SMul; SAdd]
let rec byteCode (l : sInstr list) : string =
match l with
| [] -> ""
| (SC n :: l) -> "0 " + string n + " " + byteCode l
| (SAdd :: l) -> "1 " + byteCode l
| (SSub :: l) -> "2 " + byteCode l
| (SMul :: l) -> "3 " + byteCode l
| (SNeg :: l) -> "4 " + byteCode l
| (SLess :: l) -> "5 " + byteCode l
| (SIfze n :: l) -> "6 " + string n + " " + byteCode l
| (SJump n :: l) -> "7 " + string n + " " + byteCode l
This probably won't compile because I didn't give my entire program.
This returns: "0 10 0 2 1 0 32 0 4 0 5 1 3 1 "
I expect: "0 10 0 2 1 0 32 0 4 0 5 1 3 1"
Cases like this are usually signs that strings are concatenated in a way that is too naive. Consider first collecting all the individual components of your result and then calling the predefined String.concat function:
let byteCode (l : sInstr list) : string =
let rec byteCode' l =
match l with
| [] -> []
| (SC n :: l) -> "0" :: string n :: byteCode' l
| (SAdd :: l) -> "1" :: byteCode' l
| (SSub :: l) -> "2" :: byteCode' l
| (SMul :: l) -> "3" :: byteCode' l
| (SNeg :: l) -> "4" :: byteCode' l
| (SLess :: l) -> "5" :: byteCode' l
| (SIfze n :: l) -> "6" :: string n :: byteCode' l
| (SJump n :: l) -> "7" :: string n :: byteCode' l
l |> byteCode' |> String.concat " "
String.concat already only adds the separator string between the individual parts.
This is also much cleaner, because it keeps the implementation detail of the specific separator string out of your core logic and makes it much more easily replaceable - imagine the effort of simply changing it to two spaces in your function.
Alternatively, you can just use your existing function, and on the final resulting string call the .Trim() (or .TrimEnd()) method to remove (trailing) spaces.
You could avoid recursion in this manner:
let byteCode (l : sInstr list) : string =
let instrToString (bc : sInstr) : string =
match bc with
| (SC n) -> sprintf "0 %d" n
| (SAdd ) -> "1"
| (SSub ) -> "2"
| (SMul ) -> "3"
| (SNeg ) -> "4"
| (SLess ) -> "5"
| (SIfze n) -> sprintf "6 %d" n
| (SJump n) -> sprintf "7 %d" n
l |> List.map instrToString |> String.concat " "
Supposed sInstr is defined as:
type sInstr =
| SC of int
| SAdd
| SSub
| SMul
| SNeg
| SLess
| SIfze of int
| SJump of int
the functions to byteCodes and revserse could look like this:
let byteCode (l : sInstr list) : string =
let instrToString (bc : sInstr) =
(match bc with
| SC n -> [0; n]
| SAdd -> [1]
| SSub -> [2]
| SMul -> [3]
| SNeg -> [4]
| SLess -> [5]
| SIfze n -> [6; n]
| SJump n -> [7; n])
String.Join(" ", (l |> List.map instrToString |> List.fold (fun acc lst -> acc # lst) []))
let toInstr (bcString : string) : sInstr list =
let rec recToInstr bcList =
match bcList with
| [] -> []
| head :: tail ->
match head with
| "0" -> SC(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
| "1" -> SAdd :: recToInstr tail
| "2" -> SSub :: recToInstr tail
| "3" -> SMul :: recToInstr tail
| "4" -> SNeg :: recToInstr tail
| "5" -> SLess :: recToInstr tail
| "6" -> SIfze(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
| "7" -> SJump(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
| _ -> []
recToInstr (bcString.Split(' ') |> Array.toList)

How to fix this bug in a math expression evaluator

I've written a typical evaluator for simple math expressions (arithmetic with some custom functions) in F#. While it seems to be working correctly, some expressions don't evaluate as expected, for example, these work fine:
eval "5+2" --> 7
eval "sqrt(25)^2" --> 25
eval "1/(sqrt(4))" --> 0.5
eval "1/(2^2+2)" --> 1/6 ~ 0.1666...
but these don't:
eval "1/(sqrt(4)+2)" --> evaluates to 1/sqrt(6) ~ 0.408...
eval "1/(sqrt 4 + 2)" --> will also evaluate to 1/sqrt(6)
eval "1/(-1+3)" --> evaluates to 1/(-4) ~ -0.25
the code works as follows, tokenization (string as input) -> to rev-polish-notation (RPN) -> evalRpn
I thought that the problem seems to occur somewhere with the unary functions (functions accepting one operator), these are the sqrt function and the negation (-) function. I don't really see what's going wrong in my code. Can someone maybe point out what I am missing here?
this is my implementation in F#
open System.Collections
open System.Collections.Generic
open System.Text.RegularExpressions
type Token =
| Num of float
| Plus
| Minus
| Star
| Hat
| Sqrt
| Slash
| Negative
| RParen
| LParen
let hasAny (list: Stack<'T>) =
list.Count <> 0
let tokenize (input:string) =
let tokens = new Stack<Token>()
let push tok = tokens.Push tok
let regex = new Regex(#"[0-9]+(\.+\d*)?|\+|\-|\*|\/|\^|\)|\(|pi|e|sqrt")
for x in regex.Matches(input.ToLower()) do
match x.Value with
| "+" -> push Plus
| "*" -> push Star
| "/" -> push Slash
| ")" -> push LParen
| "(" -> push RParen
| "^" -> push Hat
| "sqrt" -> push Sqrt
| "pi" -> push (Num System.Math.PI)
| "e" -> push (Num System.Math.E)
| "-" ->
if tokens |> hasAny then
match tokens.Peek() with
| LParen -> push Minus
| Num v -> push Minus
| _ -> push Negative
else
push Negative
| value -> push (Num (float value))
tokens.ToArray() |> Array.rev |> Array.toList
let isUnary = function
| Negative | Sqrt -> true
| _ -> false
let prec = function
| Hat -> 3
| Star | Slash -> 2
| Plus | Minus -> 1
| _ -> 0
let toRPN src =
let output = new ResizeArray<Token>()
let stack = new Stack<Token>()
let rec loop = function
| Num v::tokens ->
output.Add(Num v)
loop tokens
| RParen::tokens ->
stack.Push RParen
loop tokens
| LParen::tokens ->
while stack.Peek() <> RParen do
output.Add(stack.Pop())
stack.Pop() |> ignore // pop the "("
loop tokens
| op::tokens when op |> isUnary ->
stack.Push op
loop tokens
| op::tokens ->
if stack |> hasAny then
if prec(stack.Peek()) >= prec op then
output.Add(stack.Pop())
stack.Push op
loop tokens
| [] ->
output.AddRange(stack.ToArray())
output
(loop src).ToArray()
let (#) op tok =
match tok with
| Num v ->
match op with
| Sqrt -> Num (sqrt v)
| Negative -> Num (v * -1.0)
| _ -> failwith "input error"
| _ -> failwith "input error"
let (##) op toks =
match toks with
| Num v,Num u ->
match op with
| Plus -> Num(v + u)
| Minus -> Num(v - u)
| Star -> Num(v * u)
| Slash -> Num(u / v)
| Hat -> Num(u ** v)
| _ -> failwith "input error"
| _ -> failwith "inpur error"
let evalRPN src =
let stack = new Stack<Token>()
let rec loop = function
| Num v::tokens ->
stack.Push(Num v)
loop tokens
| op::tokens when op |> isUnary ->
let result = op # stack.Pop()
stack.Push result
loop tokens
| op::tokens ->
let result = op ## (stack.Pop(),stack.Pop())
stack.Push result
loop tokens
| [] -> stack
if loop src |> hasAny then
match stack.Pop() with
| Num v -> v
| _ -> failwith "input error"
else failwith "input error"
let eval input =
input |> (tokenize >> toRPN >> Array.toList >> evalRPN)
Before answering your specific question, did you notice you have another bug? Try eval "2-4" you get 2.0 instead of -2.0.
That's probably because along these lines:
match op with
| Plus -> Num(v + u)
| Minus -> Num(v - u)
| Star -> Num(v * u)
| Slash -> Num(u / v)
| Hat -> Num(u ** v)
u and v are swapped, in commutative operations you don't notice the difference, so just revert them to u -v.
Now regarding the bug you mentioned, the cause seems obvious to me, by looking at your code you missed the precedence of those unary operations:
let prec = function
| Hat -> 3
| Star | Slash -> 2
| Plus | Minus -> 1
| _ -> 0
I tried adding them this way:
let prec = function
| Negative -> 5
| Sqrt -> 4
| Hat -> 3
| Star | Slash -> 2
| Plus | Minus -> 1
| _ -> 0
And now it seems to be fine.
Edit: meh, seems I was late, Gustavo posted the answer while I was wondering about the parentheses. Oh well.
Unary operators have the wrong precedence. Add the primary case | a when isUnary a -> 4 to prec.
The names of LParen and RParen are consistently swapped throughout the code. ( maps to RParen and ) to LParen!
It runs all tests from the question properly for me, given the appropriate precedence, but I haven't checked the code for correctness.

F#: How to match on a substring?

I am new to F#, but not new to programming. Most of my experience is in the C# and SQL world. MSDN and other sites I've looked at haven't quite made this simple enough for my little brain yet, so I'm wondering if you can give me a nudge in the right direction.
I'm trying to write a simple function that returns true if a string is null, empty, or starts with "//", else it should return false.
#light
let thisIsACommentOrBlank line =
match line with
| null -> true
| "" -> true
| notSureWhatToPutHere -> true
| _ -> false
Thanks!
Update
Thanks to all of your suggestions, in the end, I was able to collapse everything down to a lambda as follows:
|> List.filter (fun line -> not (System.String.IsNullOrWhiteSpace(line) || line.StartsWith("//")))
Thanks again.
Here is one way to do it:
let thisIsACommentOrBlank line =
match line with
| a when System.String.IsNullOrWhiteSpace(a) || a.StartsWith("//") -> true
| _ -> false;;
You can use a when clause, like this:
let thisIsACommentOrBlank line =
match line with
| null -> true
| "" -> true
| s when s.StartsWith "//" -> true
| _ -> false
But for that matter, this is a lot simpler:
let thisIsACommentOrBlank line =
(String.IsNullOrEmpty line) || (line.StartsWith "//")
You can just omit last match:
let thisIsACommentOrBlank line =
match line with
| null -> true
| "" -> true
| s -> s.StartsWith "//"
You can use a when condition (see here):
let thisIsACommentOrBlank line =
match line with
| null -> true
| "" -> true
| s when s.StartsWith "//" -> true
| _ -> false
But your function can be optimized:
let thisIsACommentOrBlank = function
| null | "" -> true
| s -> s.StartsWith "//"

Resources