BF Interpreter in F# Issue [closed] - f#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Ok so i am working on a small project as you can tell in the title i am making an BrainFuck interpeter in f# and i am new to this language but it is fun except that you fight with the compiler lot but i am used to it cause i used to use rust but aside the point it looks like to me it is only executing the symbols once. I know this is not efficient or fully functional but right now i am just going that works. Here is my code
main.fs
open System
open System.IO
let mutable reg : int array = Array.zeroCreate 50
let mutable ptr = 0
let mutable larr : int array = Array.zeroCreate 50
let mutable lptr = 0
let mutable pc = 0
let result = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
let prog = result.ToCharArray()
let startLoop =
larr.[lptr] <- pc
printfn "STARTING LOOP AT %d" larr.[lptr]
lptr <- lptr + 1
let doEnd =
pc <- larr.[lptr]
while larr.[lptr - 1] > 0 do
ptr <- larr.[lptr - 1]
larr.[lptr - 1] <- larr.[lptr - 1] - 1
let endLoop =
lptr <- lptr - 1
if reg.[ptr] = 0 then pc <- pc
else doEnd
let doPlus =
reg.[ptr] <- (reg.[ptr] + 1) % 265
printfn "ADDING"
let doMinus =
reg.[ptr] <- (reg.[ptr] - 1) % 265
printfn "SUB"
let doInc =
ptr <- (ptr + 1) % 265
printfn "INC"
let doDec =
ptr <- (ptr - 1) % 265
printfn "MINUS"
let doPrt =
printfn "%c" (reg.[ptr] |> char)
let doSloop =
startLoop
printfn "START LOOP"
let doEloop =
endLoop
printfn "END LOOP"
let exec =
while pc < prog.Length do
let i = prog.[pc]
if i = '+' then doPlus
elif i = '-' then doMinus
elif i = '>' then doInc
elif i = '<' then doDec
elif i = '.' then doPrt
elif i = '[' then doSloop
elif i = ']' then doEloop
else 1 |> ignore
pc <- pc + 1
exec

Welcome to the F# community.
Here is a more functional style of writing your program. It's just a start, but I hope it will give you some ideas about how to proceed. Ultimately, you'll want to avoid mutable values if at all possible, and probably the first step to doing that would be to write functions that have parameters other than unit.
let result = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
let doPlus () =
// reg.[ptr] <- (reg.[ptr] + 1) % 265
printfn "ADDING"
let doMinus () =
// reg.[ptr] <- (reg.[ptr] - 1) % 265
printfn "SUB"
let doDefault () = printfn ""
let funcs =
[|
'+', doPlus
'-', doMinus
|] |> Map.ofArray
let exec () =
result
|> Seq.iteri (fun i c ->
printf "%03d: " i
match funcs.TryFind(c) with
| Some func -> func ()
| None -> doDefault ()
)
exec ()

Related

Any suggestions on how to optimize this string -> double parser further, in F#?

Part of testing, I have to load massive CSV files (200+mb each) and I'm trying to cut down the load time since this is adding up.
As the CSV files are all floating point numbers, I tried to see if I could speed that up.
One important point: I do NOT need precision beyond 5 digits after the comma. The code I post here parses it anyways to give a fair comparison to .NET's parser, but any shortcut that preserves that precision is good.
The code I came up with:
open System
open System.Diagnostics
[<EntryPoint>]
let main _ =
let r = Random()
let numbers =
seq {
for _ in 0 .. 10000000 do
let n = (1000. * r.NextDouble()) - 500.
yield (n, sprintf "%.8f" n)
}
|> Seq.toList
let parseString (number: string) : double =
let len = number.Length
let rec parse (index: int) (nSign: double) (signMultiplier: double) (nAccumulator: int64) : float =
if index < len then
match number.[index] with
| x when x >= '0' && x <= '9' -> parse (index + 1) (signMultiplier * nSign) signMultiplier (nAccumulator * 10L + int64 x - int64 '0')
| x when x = '.' -> parse (index + 1) nSign 0.1 nAccumulator
| x when x = '-' -> parse (index + 1) -nSign signMultiplier nAccumulator
| _ -> parse (index + 1) nSign signMultiplier nAccumulator
else
double nAccumulator * nSign
parse 0 +1. 1. 0L
let benchmark name (func: string -> double) =
let allowedError = 0.00001
printf "checking %s - " name
let sw = Stopwatch()
sw.Start()
numbers
|> List.iter (fun (num, str) ->
let parsed = func str
let delta = num - parsed
if abs delta > allowedError then
failwithf "(%f, %s) not matching %f" num str parsed
)
sw.Stop()
printfn "%i ms" sw.ElapsedMilliseconds
benchmark ".net parser" (fun x -> double x)
benchmark "parser1" (fun x -> parseString x)
0
Is there anything obvious I missed to speed this up?
Additionally, there is something I do not understand: I tried to make the test numbers an array instead of a list and suddenly the processing took longer, while I'd expect the opposite. If anyone has some insights as to why it is happening, I'd be happy to know. You can just change the toList to toArray and replace the List with Array in the benchmark loop to test this.
Edit:
to load the data, here is the code I use:
// load a csv file
let loadCSV (stream: Stream) =
seq {
use s = new StreamReader (stream)
while not s.EndOfStream do
yield s.ReadLine ()
}
|> Seq.map (fun line -> line.Split(",") |> Array.toList)
|> Seq.toList

How to execute specific functions with input pattern in F# language

I'm kinda new to F# and trying out a simple calculator app. I take input from the user, and I want to the specific functions to be executed as per the input.
Right now, whenever I take any input from user, the program executes top to bottom. I want it to execute only specific functions matching with the input. Like if input is 6 then body of scientificFun() should be executed. Right now it executes all functions. Please help, I'm kinda stuck on this one!
The code is
open System
let mutable ok = true
while ok do
Console.WriteLine("Choose a operation:\n1.Addition\n2.Substraction\n3.Multiplication\n4.Division\n5.Modulo\n6.Scientific")
let input= Console.ReadLine()
let add =
Console.WriteLine("Ok, how many numbers?")
let mutable count = int32(Console.ReadLine())
let numberArray = Array.create count 0.0
for i in 0 .. numberArray.Length - 1 do
let no = float(Console.ReadLine())
Array.set numberArray i no
Array.sum numberArray
let sub x y = x - y
let mul x y = x * y
let div x y = x / y
let MOD x y = x % y
let scientificFun() =
printfn("1. Exponential")
match input with
| "1" -> printfn("The Result is: %f") (add)
| "6" -> (scientificFun())
| _-> printfn("Choose between 1 and 6")
Console.WriteLine("Would you like to use the calculator again? y/n")
let ans = Console.ReadLine()
if ans = "n" then
ok <- false
else Console.Clear()
You should define add as function: let add() = or let add inputNumbers =
Otherwise this simplified version below only executes the functions corresponding to the input number:
open System
[<EntryPoint>]
let main argv =
// define your functions
let hellofun() =
printfn "%A" "hello"
let worldfun() =
printfn "%A" "world"
let mutable cont = true
let run() = // set up the while loop
while cont do
printfn "%A" "\nChoose an operation:\n 1 hellofunc\n 2 worldfunc\n 3 exit"
let input = Console.ReadLine() // get the input
match input with // pattern match on the input to call the correct function
| "1" -> hellofun()
| "2" -> worldfun()
| "3" -> cont <- false;()
| _ -> failwith "Unknown input"
run() // kick-off the loop
0
The [<EntryPoint>] let main argv = is only necessary if you compile it. Otherwise just execute run().

F# functional style approach much slower

Trying to learn F#, by solving some programming puzzles. I don't want to add too many details about the problem as I don't want to spoil the fun for others.
Basically, the issue is to find all 4-uples { (i,j,k,l) | i ^ j ^ k ^ l != 0 } with no repetition (eg., (1,1,1,2) and (1,1,2,1) are the same and should be counted just once).
I have found a O(n^3) approach which works, please see countImperative(a,b,c,d) below. But I also tried to refactor the code as to get rid of the nested for loops. However, I could not do so without a significant performance penalty. It was my impression that F#'s syntactic sugar would allow a more concise style (using pipes and folds), letting the compiler do the heavy-lifting to produce comparably fast code (compared to my nested for loops). The big performance hit comes from the calculation of the partial2 sum.
Here's the code:
open System
open System.Diagnostics
open System.Collections
module quadruples =
[<EntryPoint>]
let main argv =
let input = "2000 2000 2000 2000"
let ordered = [ for x in input.Split([|' '|]) -> Convert.ToInt32(x) ] |> List.sort
let a,b,c,d = ordered.[0], ordered.[1], ordered.[2], ordered.[3]
let inner(a,b) = a * (a-1) / 2 + a * (b-a)
let sw = new Stopwatch()
sw.Start()
let partial1 = [ 1.. b ] |> List.fold (fun acc j -> acc + (int64 ((min a j) * inner(c-j+1, d-j+1)))) 0L
sw.Stop()
let elapsed1 = (sw.ElapsedMilliseconds |> double) / 1000.0
printfn "Partial1: %f s" elapsed1
sw.Restart()
let combinations = [ for i in 1..a do for j in i+1..b do yield (j,i^^^j) ]
let range = [ 1..c ]
let partial2 = combinations |> List.fold(fun acc (j,x) -> acc + (range |> List.skip(j-1) |> List.fold(fun acc k -> if k ^^^ x < k || k ^^^ x > d then acc + 1L else acc) 0L)) 0L
sw.Stop()
let elapsed2 = (sw.ElapsedMilliseconds |> double) / 1000.0
printfn "Partial2: %f s" elapsed2
printfn "Functional: %d, Elapsed: %f s" (partial1 + partial2) (elapsed1 + elapsed2)
// "imperative" approach
let countImperative(a,b,c,d) =
let mutable count = seq { 1..b } |> Seq.fold (fun acc j -> acc + (int64 ((min a j) * inner(c-j+1, d-j+1)))) 0L
for i in 1..a do
for j in i+1..b do
let x = i ^^^ j
for k in j..c do
let y = x ^^^ k
if y < k || y > d then
count <- count + 1L
count
sw.Restart();
let count = countImperative(a,b,c,d)
sw.Stop()
printfn "Imperative: %d, Elapsed: %f s" count ((sw.ElapsedMilliseconds |> double) / 1000.0)
0 // return an integer exit code
So my question was, if there is any way to speed up the code (specifically the calculation of partial2) while maintaining F#'s nice syntax.

How to replace an element of a string at a given index

string s = "foo.bar"
s[s.LastIndexOf(".")] = "-"
It sounds dead simple in c-like languages, but drives me nuts in F#
my code:
let sb = new StringBuilder(s)
sb.[s.LastIndexOf(".")] <- '-'
let s = sb.ToString()
Is there more elegant way to do this? Like using |> ? I don't want to explicitly declare a new variable sb.
Alternatively, you can do this as follows:
let s = "foo.bar"
let index = s.LastIndexOf('.')
let s1 = s |> String.mapi(fun i x -> if i=index then '-' else x)
s1 |> printfn "%A"
Print: "foo-bar"
Link: https://dotnetfiddle.net/5FjFR1
There are already good suggestions here. Here's another way to do it:
let s = "foo.bar"
let idx = s.LastIndexOf '.'
let replaced = s.Substring(0, idx) + "-" + s.Substring(idx + 1)
You could work with char array directly instead of wrapped with StringBuilder.
let replaceAt i c (s: string) =
let arr = s.ToCharArray()
arr.[i] <- c
String arr
"foo.bar" |> replaceAt 3 '-'
Some tests comparing it with this one using mapi—
let replaceAt2 index x s = s |> String.mapi (fun i x -> if i=index then '-' else x)
let test f =
let rec loop n =
if n > 0 then
let x = "foo.bar" |> f 3 '-'
loop (n - 1)
loop 10000000
test replaceAt // Real: 00:00:01.188, CPU: 00:00:01.201, GC gen0: 168, gen1: 168, gen2: 0
test replaceAt2 // Real: 00:00:05.587, CPU: 00:00:05.584, GC gen0: 275, gen1: 275, gen2: 0
Just for the fun of it I tried a "more" functional approach with List.foldBack. Try the code below for yourself at .NET Fiddle.
let replaceLastOf candidate replacement l =
let replaceAndPrepend x (xs, found) =
if not found && x = candidate
then (replacement::xs, true)
else (x::xs, found)
fst <| List.foldBack replaceAndPrepend l ([], false)
let replaceLastCharOf candidate replacement (str:string) =
List.ofSeq str
|> replaceLastOf candidate replacement
|> Array.ofList
|> System.String.Concat
Usage:
printfn "%A" (replaceLastOf 1 9 [1;3;1;4;1])
printfn "%A" (replaceLastCharOf '.' '-' "f.oo.bar")
Output:
[1; 3; 1; 4; 9]
"f.oo-bar"

OCaml: Stream.peek without consuming line?

I'm working on a program that iterates over an input file, with a variable number of 'programs', and ending in '0'. My function run works fine if I start it from the top of the file, but for some reason a line is consumed by peeking to see if the next char is '0' (indicating the end of the file).
Here's my code:
let line_stream_of_channel channel =
Stream.from
(fun _ ->
try Some (input_line channel) with End_of_file -> None);;
let in_channel = open_in "dull.in" in
let line_stream = line_stream_of_channel in_channel in
while Stream.peek line_stream != Some "0" do
run in_channel;
print_string "...\n";
done;;
From what I've read, Stream.peek shouldn't consume a line, so maybe the problem doesn't come from that, but if not, I can't figure out what's doing it. Any ideas?
Edit Here's the entirety of my program:
let hello c =
print_char c;;
let hello_int c =
print_int c;
print_char '\n';;
let ios = int_of_string;;
let rec print_string_list = function
[] -> print_string "\n"
| h::t -> print_string h ; print_string " " ; print_string_list t;;
let rec print_int_list = function
[] -> print_string "\n"
| h::t -> print_int h ; print_string " " ; print_int_list t;;
let rec append l i =
match l with
[] -> [i]
| h :: t -> h :: (append t i);;
let line_stream_of_channel channel =
Stream.from
(fun _ ->
try Some (input_line channel) with End_of_file -> None);;
let string_to_int_list str_list int_list=
let len = List.length str_list in
for i = 0 to len - 1 do
int_list := append !int_list (ios (List.nth str_list i));
done;;
let get_option = function
| Some x -> x
| None -> raise (Invalid_argument "Option.get");;
let chomp_line ns in_channel =
let s = input_line in_channel in
let len = String.length s in
let start_pos = ref 0 in
for i = 0 to len do
if i == len then
let word = String.sub s !start_pos (i - !start_pos) in
ns := append !ns word;
else if s.[i] == ' ' then
let word = String.sub s !start_pos (i - !start_pos) in
ns := append !ns word;
start_pos := i + 1;
done;;
let run in_channel =
let ns = ref [] in
chomp_line ns in_channel;
let n = ios (List.nth !ns 0) in
let p = ios (List.nth !ns 1) in
let s = ios (List.nth !ns 2) in
print_string "num dulls: "; hello_int n;
print_string "num programs: "; hello_int p;
print_string "num state transitions: "; hello_int s;
let dull_sizes = ref [] in
chomp_line dull_sizes in_channel;
let int_dull_sizes = ref [] in
string_to_int_list !dull_sizes int_dull_sizes;
print_string "size of dulls: "; print_int_list !int_dull_sizes;
let program_sizes = ref [] in
let program_dulls = ref [] in
for i = 0 to p - 1 do
let program = ref [] in
chomp_line program in_channel;
program_sizes := append !program_sizes (List.nth !program 0);
program_dulls := append !program_dulls (List.nth !program 1);
done;
let int_program_sizes = ref [] in
string_to_int_list !program_sizes int_program_sizes;
print_string "program sizes: "; print_int_list !int_program_sizes;
print_string "program dulls: "; print_string_list !program_dulls;
let transitions = ref [] in
chomp_line transitions in_channel;
let int_transitions = ref [] in
string_to_int_list !transitions int_transitions;
for i = 0 to s - 1 do
hello_int (List.nth !int_transitions i)
done
;;
let in_channel = open_in "dull.in" in
let line_stream = line_stream_of_channel in_channel in
while Stream.peek line_stream <> Some "0" do
run in_channel;
done;;
And here's a sample input:
2 2 3
500 600
100 A
200 B
2 1 2
5 4 8
100 400 200 500 300
250 AC
360 ACE
120 AB
40 DE
2 3 4 -3 1 2 -2 1
0
(!=) is physical (pointer) inequality, and the test fails to detect your end mark 0. When 0 is peeked, Stream.peek returns Some 0, but it is a different entity from Some 0 of the right hand of the inequality check, and therefore the loop never terminates until it crashes at EOF.
The following demonstrates what is happening:
# Some 0 != Some 0;;
- : bool = true
# let x = Some 0 in x != x;;
- : bool = false
Use (<>), structural inequality here. Except it and the omitted run_in_channel part, the code works fine for me.
A golden rule: do not use physical equality (==) and (!=) unless you really need them. Normally, stick to structural equalities (=) and (<>).
-- edit --
There was another issue in the code which was not originally revealed.
Once you create a stream from an in_channel. Do not touch it by yourself, until you want to close it by close_in! Let the stream the only reader of it.
The benefit of the stream is that once created, you are freed from taking care of when the actual readings happen. You could still access the channel directly, but it just ruins the benefit completely. Just do not do it. Use Stream.next or Stream.peek instead of input_line in your run.

Resources