My methodology is to attempt a problem using imperative code and then to attempt the same problem again using idiomatic functional code.
Here is the problem I am working through at the moment:
Change Return Program - The user enters a cost and then the amount of money given. The program will figure out the change and the number of quarters, dimes, nickels, pennies needed for the change.
Here is my naïve (imperative) solution:
let cost = 1.10m
let amountGiven = 2.00m
let mutable change = amountGiven - cost
while change <> 0m do
if change >= 0.25m then
Console.WriteLine "quater"
change <- change - 0.25m
else if change >= 0.10m then
Console.WriteLine "dime"
change <- change - 0.10m
else if change >= 0.05m then
Console.WriteLine "nickel"
change <- change - 0.05m
else if change >= 0.01m then
Console.WriteLine "penny"
change <- change - 0.01m
How can I write this code using functional constructs (i.e. without mutable)?
In this case the easiest way to do it is to move the mutable variable into a functions argument and use recursion (the while just becomes the halting check for the recursion):
let cost = 1.10m
let amountGiven = 2.00m
let rec giveChange change =
if change > 0 then
if change >= 0.25m then
Console.WriteLine "quater"
giveChange (change - 0.25m)
else if change >= 0.10m then
Console.WriteLine "dime"
giveChange (change - 0.10m)
else if change >= 0.05m then
Console.WriteLine "nickel"
giveChange (change - 0.05m)
else if change >= 0.01m then
Console.WriteLine "penny"
giveChange (change - 0.01m)
giveChange (amountGiven-cost)
this is the obvious translation
simplification
Now of course the double ifs are somewhat obsolete:
let rec giveChange change =
if change >= 0.25m then
Console.WriteLine "quater"
giveChange (change - 0.25m)
else if change >= 0.10m then
Console.WriteLine "dime"
giveChange (change - 0.10m)
else if change >= 0.05m then
Console.WriteLine "nickel"
giveChange (change - 0.05m)
else if change >= 0.01m then
Console.WriteLine "penny"
giveChange (change - 0.01m)
and of course the many ifs look terrible as well - let's replace them with an list:
let coins = ["quarter", 0.25m; "dime", 0.10m; "nickel", 0.05m; "penny", 0.01m]
let rec giveChange change =
match coins |> List.tryFind (fun (_,c) -> change >= c) with
| Some (name,coin) ->
Console.WriteLine name
giveChange (change-coin)
| None -> ()
I think that's a reasonable solution for now.
The none case will never happen, as we've got dimes in there (or so we hope, because if someone does not pay enough and the value becomes negative we are in trouble) - maybe we should give a somehwat better hint to this:
let coins = ["quarter", 0.25m; "dime", 0.10m; "nickel", 0.05m; "penny", 0.01m]
let rec giveChange change =
if change < 0.0m then failwith "cannot change negative amounts"
match coins |> List.tryFind (fun (_,c) -> change >= c) with
| Some (name,coin) ->
Console.WriteLine name
giveChange (change-coin)
| None -> failwith ("cannot find a coin smaller than " + string change)
things to think about
you don't really want to do the output in there do you?
this is some sort of greedy algorithm - but why does it have to do the division by repeated subtraction?
Each of these would significantly change your algorithm so I will not show you more code but you should really think about the second:
Instead of doing "1.20 -> give quarter -> give quarter -> give quarter -> give quarter -> ..." it's easy to see that you have 4 quarters in 1.20 using mod/div in a clever way :D
Related
This question already has answers here:
FirstOrDefault In F#
(4 answers)
Closed 9 years ago.
The code below throws a NullReferenceException within the FirstOrDefault() method:
open System
open System.Collections.Generic
open System.Linq
[<EntryPoint>]
let main argv =
let suspects = seq {
yield ("Frank", 1.0)
yield ("Suzie", 0.9)
yield ("John", 0.5)
// yield ("Keyser Soze", 0.3)
}
let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")
printfn "Name: %s" (fst likely)
Console.ReadLine() |> ignore
0
What's the best way to work around that? Catching it seems wrong. I could grab the iterator manually and put it in a while loop, but that's - well, wrong on so many levels.
[Edit]
I can't even do what I would do in C#, namely, check to see if the result is null or default, for two reasons: (1) The error is thrown in the FirstOrDefault() method, not when I reference the result; and (2) if I try to check for null, the compiler complains that `The type '(string * float)' does not have 'null' as a proper value':
if likely = null then
printfn "Nothing to see here"
Any suggestions?
As noted above, Seq.tryFind is the idiomatic way of achieving that. If you really must use FirstOrDefault() you could do something like this:
open System.Collections.Generic
open System.Linq
let suspects = seq {
yield Some("Frank", 1.0)
yield Some("Suzie", 0.9)
yield Some("John", 0.5)
// yield ("Keyser Soze", 0.3)
}
let likely = suspects.FirstOrDefault(fun x -> let name, confidence = x.Value
name = "Keyser Soze")
match likely with
| Some(x) -> printfn "Name: %s" (fst x)
| None -> printfn "Not Found"
You can follow hardcode null checks-polluted C# way if you want to:
...
let likely = suspects.FirstOrDefault(fun x -> x.Equals(null) || (fst x) = "Keyser Soze")
if obj.ReferenceEquals(likely, null) then
printfn "Nothing to print"
else
printfn "Name: %s" (fst x)
...
but this is against the major F# idiom upon avoiding null-checks altogether.
EDIT: It seems the alleged NullReferenceException within FirstOrDefault actively referred in comments simply does not happen! With first line of code above changed back to the original
let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")
the snippet works for the sequence of three first tuples without a problem.
There is any way to do it like C/C#?
For example (C# style)
for (int i = 0; i < 100; i++)
{
if (i == 66)
break;
}
The short answer is no. You would generally use some higher-order function to express the same functionality. There is a number of functions that let you do this, corresponding to different patterns (so if you describe what exactly you need, someone might give you a better answer).
For example, tryFind function returns the first value from a sequence for which a given predicate returns true, which lets you write something like this:
seq { 0 .. 100 } |> Seq.tryFind (fun i ->
printfn "%d" i
i=66)
In practice, this is the best way to go if you are expressing some high-level logic and there is a corresponding function. If you really need to express something like break, you can use a recursive function:
let rec loop n =
if n < 66 then
printfn "%d" n
loop (n + 1)
loop 0
A more exotic option (that is not as efficient, but may be nice for DSLs) is that you can define a computation expression that lets you write break and continue. Here is an example, but as I said, this is not as efficient.
This is really ugly, but in my case it worked.
let mutable Break = false
while not Break do
//doStuff
if breakCondition then
Break <- true
done
This is useful for do-while loops, because it guarantees that the loop is executed at least once.
I hope there's a more elegant solution. I don't like the recursive one, because I'm afraid of stack overflows. :-(
You have to change it to a while loop.
let (i, ans) = (ref 0, ref -1)
while(!i < 100 and !ans < 0) do
if !i = 66 then
ans := !i
ans
(This breaks when i gets to 66--but yes the syntax is quite different, another variable is introduced, etc.)
seq {
for i = 0 to 99 do
if i = 66 then yield ()
}
|> Seq.tryItem 0
|> ignore
Try this:
exception BreakException
try
for i = 0 to 99 do
if i = 66 then
raise BreakException
with BreakException -> ()
I know that some folks don't like to use exceptions. But it has merits.
You don't have to think about complicated recursive function. Of
cause you can do that, but sometimes it is unnecessarily bothersome
and using exception is simpler.
This method allows you to break at halfway of the loop body. (Break "flag" method is simple too but it only allows to break at the end of the loop body.)
You can easily escape from nested loop.
For these kind of problems you could use a recursive function.
let rec IfEqualsNumber start finish num =
if start = finish then false
elif
start = num then true
else
let start2 = start + 1
IfEqualsNumber start2 finish num
Recently I tried to solve a similar situation:
A list of, say, 10 pieces of data. Each of them must be queried against a Restful server, then get a result for each.
let lst = [4;6;1;8]
The problem:
If there is a failed API call (e.g. network issue), there is no point making further calls as we need all the 10 results available. The entire process should stop ASAP when an API call fails.
The naive approach: use List.map()
lst |> List.map (fun x ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
sqlComd.ExecuteScala() |> Some
with
| :? System.Data.SqlClient.SqlException as ex -> None
)
But as said, it's not optimal. When a failed API occurs, the remaining items keep being processed. They do something that is ignored at the end anyway.
The hacky approach: use List.tryFindIndex()
Unlike map(), we must store the results somewhere in the lamda function. A reasonable choice is to use mutable list. So when tryFindIndex() returns None, we know that everything was ok and can start making use of the mutable list.
val myList: List<string>
let res = lst |> List.tryFindIndex (fun x ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
myList.Add(sqlComd.ExecuteScala())
false
with
|:? System.Data.SqlClient.SqlException as ex -> true
)
match res with
| Some _ -> printfn "Something went wrong"
| None -> printfn "Here is the 10 results..."
The idiomatic approach: use recursion
Not very idiomatic as it uses Exception to stop the operation.
exception MyException of string
let makeCall lstLocal =
match lstLocal with
| [] -> []
| head::tail ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
let temp = sqlComd.ExecuteScala()
temp :: makeCall (tail)
with
|:? System.Data.SqlClient.SqlException as ex -> raise MyException ex.Message
try
let res = makeCall lst
printfn "Here is the 10 results..."
with
| :? MyException -> printfn "Something went wrong"
The old-fashion imperative approach: while... do
This still involves mutable list.
I am trying to run a function to update a grid for a game of life function written with f# and everything has to be recursive with no mutables. I want to add a pause button to my form by running the Update function asyncronously however when I do this only one square is updated. However when I step through the program without async all of the squares are updated. Any ideas why?
let buttonGrid : Button list list = (Startup ar);;
//transform buttongrid to int grid
let rec bg2ig (bg:Button list list) =
let rec innerLoop (bl:Button list) =
match bl with
|[] -> []
|x::xs -> if (x.Name = "0") then 0::(innerLoop xs) else 1::(innerLoop xs)
match bg with
|[] -> []
|y::ys -> (innerLoop y)::(bg2ig ys)
let Update (bg:Button list list)=
let ar = (bg2ig bg)
let rec innerUpdate (bg:Button list list)=
let rec arrayLoop (bl:Button list) y =
match bl with
|[] -> 0
|x::xs ->
let X = (15-xs.Length)
let n = (neighbors X y ar)
if (ar.[X].[y] = 0) then (if n=3 then buttonGrid.[X].[y].Name<-"1") else (if (n=2||n=3)=false then buttonGrid.[X].[y].Name<-"0")
if buttonGrid.[15-xs.Length].[y].Name="0"
then buttonGrid.[15-xs.Length].[y].BackColor <- Color.White
else buttonGrid.[15-xs.Length].[y].BackColor <- Color.Black
arrayLoop xs y
match bg with
|[] -> []
|y::ys ->
ignore (arrayLoop y (15-ys.Length))
innerUpdate ys
innerUpdate bg
let Running = async {
let rec SubRun (x:int) =
ignore (Update buttonGrid)
if x = 1 then
SubRun 1
else
0
ignore (SubRun 1)
do! Async.Sleep(1000)
}
let RunAll() =
Running
|> Async.RunSynchronously
|> ignore
As mentioned in the comments, Async.RunSynchronously is a wrong function for this scenario. It starts the workflow on a background thread (which is wrong, because you want to access GUI elements) and then it blocks the calling thread until the background work is done (which is wrong because you do not want to block the GUI thread).
You need to use Async.StartImmediate which starts the work on the current thread (which will be the GUI thread) without blocking. When the first part of the workflow completes (before Sleep) the GUI thread is free to do other work. After Sleep the workflow will again continue on the GUI thread (this is done automatically thanks to StartImmediate) and so you can again access the GUI.
Aside, your SubRun function that does the actual looping needs to be asynchronous too - so I'd expect the main part of the loop to look something like this:
let Running = async {
let rec SubRun (x:int) =
// Perform update and then sleep before recursive call
ignore (Update buttonGrid)
do! Async.Sleep(1000)
if x = 1 then
return! SubRun 1
else
return 0 }
// Start the loop and asynchronously ignore the result
SubRun 1 |> Async.Ignore
let RunAll() =
// Start the computation immediately on the current threada
Running |> Async.StartImmediate
Tomas Petricek solved the initial issue I was having but in order to make things correctly I ended up solving it differently. I think my initial issue may have been stemming from updating the form incorrectly or not at all and thus it looked very wrong.
I ended up writing my async function like this
let rec async1(syncContext, form : System.Windows.Forms.Form, cancellationSource:CancellationTokenSource, (limit:int)) =
async {
do! Async.SwitchToContext(syncContext)
ignore (Update buttonGrid)
do! Async.SwitchToThreadPool()
do! Async.Sleep(300)
if limit > 1 then
ignore (Async.Start (async1(syncContext, form, cancellationSource, (limit-1)),cancellationSource.Token))
else if limit = -1 then
ignore (Async.Start (async1(syncContext, form, cancellationSource, limit),cancellationSource.Token))
}
and then I can call on it like this witha start and stop button
let b = new Button(Location=new Point(50,500), Text=("Run"), Width=100, Height=40)
let btnPause = new Button(Location=new Point(150, 500), Text="Stop", Width=100, Height=40, Enabled=false)
b.Click.Add(fun _ ->
let cancellationSource = new CancellationTokenSource()
b.Enabled <- false
btnPause.Enabled <- true
btnSave.Enabled <- false
btnLoad.Enabled <- false
btnStep.Enabled <- false
inputBox.Enabled <- false
btnPause.Click.Add(fun _ ->
b.Enabled <- true
btnPause.Enabled <- false
btnSave.Enabled <- true
btnLoad.Enabled <- true
btnStep.Enabled <- true
inputBox.Enabled <- true
cancellationSource.Cancel())
ignore (Async.Start (async1(syncContext, form, cancellationSource, (int inputBox.Text)),cancellationSource.Token))
ignore (inputBox.Text <- "0"))
I have also added a step button for stepping through the program and an input box where I can run the program endlessly until the cancel token is called or have it run through an n number of times and then stop
In an effort to understand the capabilities of functional programming I put together a few basic functions that you can compose together to build complex regular expressions. Now after some testing I have found this works but you can write some horrible code in any language that will work. Is this the kind of code you would find a professional F# programmer writing or am I abusing the feature?
Note: test is specifically what I am referring to.
type State = { input:string; index:int; succeeded:bool }
type Matcher = State -> State
let term (cs:char Set) =
fun s ->
if s.succeeded && s.index < s.input.Length && cs.Contains s.input.[s.index] then
{ input = s.input; index = s.index + 1; succeeded = true }
else
{ input = s.input; index = s.index; succeeded = false }
let quantify (term, min, max) =
let rec inner (s:State, count) =
if s.succeeded && s.index < s.input.Length && count <= max then
inner (term { input = s.input; index = s.index + 1; succeeded = true }, count + 1)
elif count >= min && count <= max then
{ input = s.input; index = s.index - 1; succeeded = true }
else
s
fun s -> inner (s, 0)
let disjunction leftTerm rightTerm =
fun s ->
let left = leftTerm s
if not left.succeeded then
let right = rightTerm s
if not right.succeeded then
{ input = s.input; index = s.index; succeeded = false }
else
right
else
left
let matcher input terms =
let r = terms { input = input; index = 0; succeeded = true }
if r.succeeded then r.input.Substring (0, r.index) else null
let test = // (abc|xyz)a{2,3}bc
disjunction // (abc|xyz)
(term (set "a") >> term (set "b") >> term (set "c"))
(term (set "x") >> term (set "y") >> term (set "z"))
>> quantify (term (set "a"), 2, 3) // (a{2,3})
>> term (set "b") // b
>> term (set "c") // c
let main () : unit =
printfn "%s" (matcher "xyzaabc" test)
System.Console.ReadKey true |> ignore
main()
The code looks pretty good to me.
I'm not sure if this was your intention or a coincidence, but you're implementing something quite similar to "parser combinators", which is a topic of many academic papers :-). I think that Monadic Parser Combinators is quite readable (it has examples in Haskell, but you should be able to translate them to F#).
Regarding the function composition operator. I'm generally not a big fan of using the operator too much, because it often obfuscates the code. However, in your example it makes a good sense because you can easily imagine that >> means "this group should be followed by that group", which is easy to interpret.
The only minor change that I would do is to choose some nice custom operator for the disjunction operation and define a few more primitive operations, so that you can write for example this:
// Test against several terms in sequence
let sequence terms = (fun state -> terms |> Seq.fold (>>) state)
// Test for a substring
let substring s = sequence [ for c in s -> term (set [c]) ]
let test = // (abc|xyz)a{2,3}bc
( substring "abc" <|> substring "xyz" )
>> quantify 2 3 (term (set "a")) // (a{2,3})
>> substring "bc" // bc
This is more higher-level description, so it removes some of the >> operators in favor of functions that are more descriptive (and encapsulate >>). I also changed quantify to take multiple arguments instead of a tripple (which is a minor change)
If you want to play with this further, then you can take a look at the article and try to write F# computation expression builder that would allow you to use parser { .. } syntax.
This is generally good style but you're missing some tricks and still have quite a bit of redundancy. Maybe more like this:
let valid (s: State) = s.succeeded && s.index < s.input.Length
...
let disjunction leftTerm rightTerm s =
let left = leftTerm s
if left.succeeded then left else
let right = rightTerm s
if right.succeeded then right else
{ s with succeeded = false }
...
let test =
let f s = set s |> term
let (++) s t = f s >> f t
disjunction ("a" ++ "b" ++ "c") ("x" ++ "y" ++ "z")
>> quantify (f "a", 2, 3)
>> "b" ++ "c"
You might prefer to accumulate a value representing a computation rather than closures because it makes debugging much easier.
How to break after first if?
let WithdrawalCash (account, amount) = seq {
if ( account.Balance.CurrentAmount - amount < 0.0m) then
yield NotEnoughMoneyForWithdrawal(account, amount)
// How to break here?
let newBalance = account.Balance.CurrentAmount - amount
yield CashWithdrawnEvent(account, newBalance)
}
Not sure this will help, why not use the else clause?
let WithdrawalCash (account, amount) = seq {
if ( account.Balance.CurrentAmount - amount < 0.0m) then
yield NotEnoughMoneyForWithdrawal(account, amount)
// How to break here?
else
let newBalance = account.Balance.CurrentAmount - amount
yield CashWithdrawnEvent(account, newBalance)
}
Also have a look at:
Imperative computation in F# (II.) - Writing break and continue
The code as posted will only evern return one CashWithdrawlEvent, then end the sequence... you need to have a loop to return multiple values. Also, have you considered using "match" to handle multiple cases?
(not tested as working...)
let WithdrawalCash (account, amount) = seq {
let bDone = ref false
while not (!bDone) do
match amount with
| v when account.Balance.CurrentAmount - v < 0 ->
yield NotEnoughMoneyForWithdrawal(account, amount)
bDone := true // break
// more when clauses can go here
| _ ->
let newBalance = account.Balance.CurrentAmount - amount
yield CashWithdrawnEvent(account, newBalance)
// let the sequence continue
}
But, even this does not seem like what you would want, since it will ALWAYS withdraw the same 'amount' each time you pull a value from the sequence, because account and amount are fixed when the sequence is created. So, I'd drop the 'seq' and make this a simple function, as in:
let WithdrawalCash (account, amount) =
match amount with
| v when account.Balance.CurrentAmount - v < 0 ->
NotEnoughMoneyForWithdrawal(account, amount)
// more when clauses can go here
| _ ->
let newBalance = account.Balance.CurrentAmount - amount
CashWithdrawnEvent(account, newBalance)
For the general case of enumerating some sequence and stopping when a particular condition is met, consider "Seq.takeWhile", as in:
let MySeq = seq {
while true do
yield someValue
}
let code () =
MySeq
|> Seq.takeWhile ( fun v -> ShouldIContinueWorkingTest(v) )
|> Seq.iter ( fun v -> DoWork(v) )
As this is the only relevant question in SO about yield break in F#, I think I should add this for the sake of completeness. In the OP's question one could get away with the else. But what do you do if you really need to break? what if you have to deal with match? Let's assume that you have a discriminated union like this
type SomeUnion =
| Foo of SomeType
| Bar of SomeType * SubclassOfSomeType
| Indifferent of IncompatibleType
and you want to get a sequence of SomeType and SubclassOfSomeType and ignore the rest:
let private toSomeType (arg:SomeUnion) =
seq {
match arg with
| Foo foo -> yield foo
| Bar (one, two) -> yield one; yield two
| Indifferent _ -> () (*<- effectively this is your 'yield break'*)
}
I used Indifferent as it was my only remaining case. Obviously one could simply use | _ -> () to ignore a gazillion of cases, I just prefer to see the warning if I add another case in the future.
I hope that this is a correct technique as I am an absolute beginner in F# and I had to chase my tail for some time to get around this. Feel free to let me know in the comments if there is a better way.