I'm new to F# and I'm coding little challenges to learn the nitty-gritty details about the language. I think I have a problem because of immutability.
Scenario:
I have to read height lines in the console, each line contains one integer. That integer represent the size of a mountain.
After reading the input i need to write the line number of the highest mountains.
If the index given is the highest mountain then the size is set to zero else I loose.
Repeat the scenario until all mountains have their size set to zero.
Here the code I wrote:
open System
type Mountain = {Id:int; Height:int}
let readlineInt() = int(Console.In.ReadLine())
let readMountainData id = {Id = id; Height = readlineInt()}
let readAllMountainsData = [ for a in 0 .. 7 do yield readMountainData a ]
let rec mainLoop () =
let mountains = readAllMountainsData
let highestMountain = mountains |> List.maxBy (fun x -> x.Height)
printfn "%i" highestMountain.Id
mainLoop()
mainLoop()
This code is going to an infinite loop, I believe it's because the
let readlineInt() = int(Console.In.ReadLine())
is immutable, so the value is set once and after it's never stop again to read the line. I try to put 'mutable' keyword for
let mutable readAllMountainsData = [ for a in 0 .. 7 do yield readMountainData a ]
But it didn't change a thing.
Do you have any idea?
Edit:
I know that this code is going into an infinite loop because after adding logging into the main loop as follow:
let rec mainLoop () =
let mountains = readAllMountainsData
Console.Error.WriteLine("Mountain Count:{0} ", mountains.Length)
mountains |> List.iter (fun x -> Console.Error.WriteLine("Mountain Id:{0} Height:{1}", x.Id, x.Height))
let highestMountain = mountains |> List.maxBy (fun x -> x.Height)
printfn "%i" highestMountain.Id
mainLoop()
Then I have this in the output:
Standard Error Stream:
Mountain Count:8
Mountain Id:0 Height:9
Mountain Id:1 Height:8
Mountain Id:2 Height:7
Mountain Id:3 Height:6
Mountain Id:4 Height:5
Mountain Id:5 Height:4
Mountain Id:6 Height:3
Mountain Id:7 Height:2
Mountain Count:8
Mountain Id:0 Height:9
Mountain Id:1 Height:8
Mountain Id:2 Height:7
Mountain Id:3 Height:6
Mountain Id:4 Height:5
Mountain Id:5 Height:4
Mountain Id:6 Height:3
Mountain Id:7 Height:2
Mountain Count:8
Mountain Id:0 Height:9
Mountain Id:1 Height:8
Mountain Id:2 Height:7
etc...
Why do I want to reread the value? Because the values are provided by an external source. So the workflow is as follow:
Loop one:
I read 8 values for the height of the mountains in the console
I output the value of the highest mountain
Loop two:
I read 8 values for the height of the mountains in the console
I output the value of the highest mountain
Loop three:
I read 8 values for the height of the mountains in the console
I output the value of the highest mountain
etc
let readlineInt () = ... defines a function. It's body will be executed every time you call it. And in this case the body has a side-effect and that side-effect (reading from stdin) will be executed every time the body is executed. So that's not your problem.
readAllMountainsData is defined to be a list containing the data of seven mountains. Each of those mountains will have its own height (because readLineInt() is called once for each mountain). This list is calculated once and does not change after that. It is not re-calculated every time you use readAllMountainsData as it is a variable, not a function (even though the name might suggest otherwise). That seems perfectly sensible as re-reading the mountain data every time would make no sense.
Adding the mutable keyword to the definition allows you to re-assign the variable. That is, it allows you to write readAllMountainsData <- someNewValue later in the program to change the variable's value. Since you never actually do that, nothing changes.
The reason that your program loops infinitely is that mainLoop always calls itself again. It has no exit condition. So to fix that you should decide how often you want to loop / under which condition you want to exit, and then implement that logic accordingly.
In your edit you clarified, that you do want to re-read your values, so you simply need to make readAllMountainsData a function by giving it a parameter list (let readAllMountainsData () = ...) and then call it as a function. This way you'll get new data on each iteration, but the loop will still be infinite unless you add an exit condition.
Related
On my mission to master F# I'm creating a pocket game.
I'm at the point where I want to implement some sort of a highscore list.
So far I'm writing Name, Score and Time to a file which then reads in to the application displaying all previous scores. Yes, this isn't ideal as the list grows pretty quick.
I somewhat want to pick the top 3 scores, not caring about Name or Time.
Question: Should I read the file into an array/list and from there pick out the top scores or is there a nicer way to pick out the top scores directly from the file?
Pointers, Code, Tips and Tricks are warmly welcome.
let scoreFile = sprintf ("Name: %s\nTime: %i sec\nScore: %d\n\n") name stopWatch.Elapsed.Seconds finalScore
let readExistingFile = File.ReadAllText ("hiscore.txt")
File.WriteAllText ("hiscore.txt", scoreFile + readExistingFile)
let msg = File.ReadAllText ("hiscore.txt")
printfn "\nHighscores:\n\n%s\n\n\n\nPress ANY key to quit." msg
Should I read the file into an array/list and from there pick out the top scores or is there a nicer way to pick out the top scores directly from the file?
Unless the scores are already sorted in the file, you'll have to look through them all to find out what the Top 3 is. The way your file is written right now, parsing the data back might be a bit hard - scores are stored on multiple lines, so you'd have to handle that.
Assuming the file doesn't have to be human-friendly, I'd go with a list of comma-separated values instead. It's harder for a human to read by opening the file, but it makes it a lot easier to parse in your program. For example, if the lines looks like Name,Time,Score, they can be parsed like this:
type ScoreData = {
Name : string
Time : string // could be a DateTime, using string for simplicity
Score : int
}
let readHighScores file =
File.ReadAllLines file
|> Array.choose (fun line ->
match line.Split ',' with
| [| name; time; score |] ->
{
Name = name
Time = time
Score = (int)score // This will crash if the score isn't an integer - see paragraph below.
}
|> Some
| _ ->
// Line doesn't match the expected format, we'll just drop it
None
)
|> Array.sortBy (fun scoreData -> -scoreData.Score) // Negative score, so that the highest score comes first
|> Seq.take 3
This will read through your file and output the three largest scores. Using Array.choose allows you to only keep lines that match the format you're expecting. This also lets you add extra validation as needed, such as making sure that the score is an integer and perhaps parsing the Time into a System.DateTime instead of storing it as an int.
You can then print your high scores by doing something like this:
let highScores = readHighScores "hiscore.txt"
printfn "High scores:"
highScores
|> Seq.iteri (fun index data ->
printfn "#%i:" (index + 1)
printfn " Name: %s" data.Name
printfn " Time: %s" data.Time
printfn " Score: %i" data.Score
)
This calls the previously defined function and prints each of the scores returned - the top 3, in this case. Using Seq.iteri, you can include the index in the output in addition to the score data itself. Using some data I made up, it ends up looking like this:
High scores:
#1:
Name: Awots
Time: 2015-06-15
Score: 2300
#2:
Name: Roujo
Time: 2016-03-01
Score: 2200
#3:
Name: Awots
Time: 2016-03-02
Score: 2100
Now, there might be a way to do this without loading the entire file at once in memory, but I don't think it'd be worth it unless you have a really large file - in which case you might want to either keep it sorted or use a more fit storage method like a database.
I've been using F# for nearly six months and have been so sure that F# Interactive should have the same performance as compiled, that when I bothered to benchmark it, I was convinced it was some kind of compiler bug. Though now it occurs to me that I should have checked here first before opening an issue.
For me it is roughly 3x slower and the optimization switch does not seem to be doing anything at all.
Is this supposed to be standard behavior? If so, I really got trolled by the #time directive. I have the timings for how long it takes to sum 100M elements on this Reddit thread.
Update:
Thanks to FuleSnabel, I uncovered some things.
I tried running the example script from both fsianycpu.exe (which is the default F# Interactive) and fsi.exe and I am getting different timings for two runs. 134ms for the first and 78ms for the later. Those two timings also correspond to the timings from unoptimized and optimized binaries respectively.
What makes the matter even more confusing is that the first project I used to compile the thing is a part of the game library (in script form) I am making and it refuses to compile the optimized binary, instead switching to the unoptimized one without informing me. I had to start a fresh project to get it to compile properly. It is a wonder the other test compiled properly.
So basically, something funky is going on here and I should look into switching fsianycpu.exe to fsi.exe as the default interpreter.
I tried the example code in pastebin I don't see the behavior you describe. This is the result from my performance run:
.\bin\Release\ConsoleApplication3.exe
Total iterations: 300000000, Outer: 10000, Inner: 30000
reduce sequence of list, result 450015000, time 2836 ms
reduce array, result 450015000, time 594 ms
for loop array, result 450015000, time 180 ms
reduce list, result 450015000, time 593 ms
fsi -O --exec .\Interactive.fsx
Total iterations: 300000000, Outer: 10000, Inner: 30000
reduce sequence of list, result 450015000, time 2617 ms
reduce array, result 450015000, time 589 ms
for loop array, result 450015000, time 168 ms
reduce list, result 450015000, time 603 ms
It's expected that Seq.reduce would be the slowest, the for loop the fastest and that the reduce on list/array is roughly similar (this assumes locality of list elements which isn't guaranteed).
I rewrote your code to allow for longer runs w/o running out of memory and to improve cache locality of data. With short runs the uncertainity of measurements makes it hard to compare the data.
Program.fs:
module fs
let stopWatch =
let sw = new System.Diagnostics.Stopwatch()
sw.Start ()
sw
let total = 300000000
let outer = 10000
let inner = total / outer
let timeIt (name : string) (a : unit -> 'T) : unit =
let t = stopWatch.ElapsedMilliseconds
let v = a ()
for i = 2 to outer do
a () |> ignore
let d = stopWatch.ElapsedMilliseconds - t
printfn "%s, result %A, time %d ms" name v d
[<EntryPoint>]
let sumTest(args) =
let numsList = [1..inner]
let numsArray = [|1..inner|]
printfn "Total iterations: %d, Outer: %d, Inner: %d" total outer inner
let sumsSeqReduce () = Seq.reduce (+) numsList
timeIt "reduce sequence of list" sumsSeqReduce
let sumsArray () = Array.reduce (+) numsArray
timeIt "reduce array" sumsArray
let sumsLoop () =
let mutable total = 0
for i in 0 .. inner - 1 do
total <- total + numsArray.[i]
total
timeIt "for loop array" sumsLoop
let sumsListReduce () = List.reduce (+) numsList
timeIt "reduce list" sumsListReduce
0
Interactive.fsx:
#load "Program.fs"
fs.sumTest [||]
PS. I am running on Windows with Visual Studio 2015. 32bit or 64bit seemed to make only marginal difference
I'm trying to plot the first 100 values of this random walk function using F#/Xamarin. Whenever I call the function, my application freezes. I tried to get the count on this.RW, but that also freezes the application. Help appreciated!
module SimulatingAndAnalyzingAssetPrices =
type RandomWalk(price : float) =
let sample = Normal(0.0, 1.0).Sample()
// Generate random walk from 'value' recursively
let rec randomWalk price =
seq {
yield price
yield! randomWalk (price + sample)
}
let rw = randomWalk 10.0
member this.RW = rw
Note: This is from tryfsharp.org's finance section. My intent is to port it to iOS using Xamarin.
Edit:
Tried using the following code, but still getting an infinite sequence:
let rw = randomWalk 10.0
let rwTake = Seq.take 100 rw
member this.RwTake = rwTake
Edit 2: Also tried
let rw = randomWalk 10.0 |> Seq.take 100
member this.RwTake = rw
Your randomWalk function produces an infinite sequence, so you should never call it without using Seq.take to limit the number of items to, say, the 100 you're trying to graph. If you call it directly, the app freezes because you'll never find the end of the infinite sequence. But if you graph somePrice |> this.RW |> Seq.take 100, you should no longer have your application freezing up any more.
And getting the count of an infinite sequence is also going to freeze up, because it will be going through the sequence trying to reach the end so it can return a count, but there's no end! You can never take a count of an infinite sequence.
Update: There's also Seq.truncate. The difference between Seq.take and Seq.truncate lies in what happens if there are fewer items than expected. (This won't be the case for your randomWalk function, so you can use either take or truncate and you'll be fine, but in other situations you might need to know the difference.) If a sequence has only 5 items but you try to Seq.take 10 from it, it will throw an exception. Seq.truncate, on the other hand, will return just 5 items.
So Seq.take 10 will either return exactly 10 items, no more nor less, or else throw an exception. Seq.truncate 10 will return up to 10 items, but might return fewer, and will never throw an exception.
For more details, see Does F# have an equivalent to Haskell's take?
Extremely just-started-yesterday new to F#.
What I want: To write code that parses the string "2 + 2" into (using as an example code from the tutorial project) Expr.Add(Expr.Num 2, Expr.Num 2) for evaluation. Some help to at least point me in the right direction or tell me it's too complex for my first F# project. (This is how I learn things: By bashing my head against stuff that's hard)
What I have: My best guess at code to extract the numbers. Probably horribly off base. Also, a lack of clue.
let script = "2 + 2";
let rec scriptParse xs =
match xs with
| [] -> (double)0
| y::ys -> (double)y
let split = (script.Split([|' '|]))
let f x = (split[x]) // "This code is not a function and cannot be applied."
let list = [ for x in 0..script.Length -> f x ]
let result = scriptParse
Thanks.
The immediate issue that you're running into is that split is an array of strings. To access an element of this array, the syntax is split.[x], not split[x] (which would apply split to the singleton list [x], assuming it were a function).
Here are a few other issues:
Your definition of list is probably wrong: x ranges up to the length of script, not the length of the array split. If you want to convert an array or other sequence to a list you can just use List.ofSeq or Seq.toList instead of an explicit list comprehension [...].
Your "casts" to double are a bit odd - that's not the right syntax for performing conversions in F#, although it will work in this case. double is a function, so the parentheses are unnecessary and what you are doing is really calling double 0 and double y. You should just use 0.0 for the first case, and in the second case, it's unclear what you are converting from.
In general, it would probably be better to do a bit more design up front to decide what your overall strategy will be, since it's not clear to me that you'll be able to piece together a working parser based on your current approach. There are several well known techniques for writing a parser - are you trying to use a particular approach?
I have pieces of code like this in a project and I realize it's not
written in a functional way:
let data = Array.zeroCreate(3 + (int)firmwareVersions.Count * 27)
data.[0] <- 0x09uy //drcode
data.[1..2] <- firmwareVersionBytes //Number of firmware versions
let mutable index = 0
let loops = firmwareVersions.Count - 1
for i = 0 to loops do
let nameBytes = ASCIIEncoding.ASCII.GetBytes(firmwareVersions.[i].Name)
let timestampBytes = this.getTimeStampBytes firmwareVersions.[i].Timestamp
let sizeBytes = BitConverter.GetBytes(firmwareVersions.[i].Size) |> Array.rev
data.[index + 3 .. index + 10] <- nameBytes
data.[index + 11 .. index + 24] <- timestampBytes
data.[index + 25 .. index + 28] <- sizeBytes
data.[index + 29] <- firmwareVersions.[i].Status
index <- index + 27
firmwareVersions is a List which is part of a csharp library.
It has (and should not have) any knowledge of how it will be converted into
an array of bytes. I realize the code above is very non-functional, so I tried
changing it like this:
let headerData = Array.zeroCreate(3)
headerData.[0] <- 0x09uy
headerData.[1..2] <- firmwareVersionBytes
let getFirmwareVersionBytes (firmware : FirmwareVersion) =
let nameBytes = ASCIIEncoding.ASCII.GetBytes(firmware.Name)
let timestampBytes = this.getTimeStampBytes firmware.Timestamp
let sizeBytes = BitConverter.GetBytes(firmware.Size) |> Array.rev
Array.concat [nameBytes; timestampBytes; sizeBytes]
let data =
firmwareVersions.ToArray()
|> Array.map (fun f -> getFirmwareVersionBytes f)
|> Array.reduce (fun acc b -> Array.concat [acc; b])
let fullData = Array.concat [headerData;data]
So now I'm wondering if this is a better (more functional) way
to write the code. If so... why and what improvements should I make,
if not, why not and what should I do instead?
Suggestions, feedback, remarks?
Thank you
Update
Just wanted to add some more information.
This is part of some library that handles the data for a binary communication
protocol. The only upside I see of the first version of the code is that
people implementing the protocol in a different language (which is the case
in our situation as well) might get a better idea of how many bytes every
part takes up and where exactly they are located in the byte stream... just a remark.
(As not everybody understand english, but all our partners can read code)
I'd be inclined to inline everything because the whole program becomes so much shorter:
let fullData =
[|yield! [0x09uy; firmwareVersionBytes; firmwareVersionBytes]
for firmware in firmwareVersions do
yield! ASCIIEncoding.ASCII.GetBytes(firmware.Name)
yield! this.getTimeStampBytes firmware.Timestamp
yield! BitConverter.GetBytes(firmware.Size) |> Array.rev|]
If you want to convey the positions of the bytes, I'd put them in comments at the end of each line.
I like your first version better because the indexing gives a better picture of the offsets, which are an important piece of the problem (I assume). The imperative code features the byte offsets prominently, which might be important if your partners can't/don't read the documentation. The functional code emphasises sticking together structures, which would be OK if the byte offsets are not important enough to be mentioned in the documentation either.
Indexing is normally accidental complexity, in which case it should be avoided. For example, your first version's loop could be for firmwareVersion in firmwareVersion instead of for i = 0 to loops.
Also, like Brian says, using constants for the offsets would make the imperative version even more readable.
How often does the code run?
The advantage of 'array concatenation' is that it does make it easier to 'see' the logical portions. The disadvantage is that it creates a lot of garbage (allocating temporary arrays) and may also be slower if used in a tight loop.
Also, I think perhaps your "Array.reduce(...)" can just be "Array.concat".
Overall I prefer the first way (just create one huge array), though I would factor it differently to make the logic more apparent (e.g. have a named constant HEADER_SIZE, etc.).
While we're at it, I'd probably add some asserts to ensure that e.g. nameBytes has the expected length.