patternMinor
My Brainfuck interpreter in F#
Viewed 0 times
brainfuckinterpreterstackoverflow
Problem
I'm very new to functional world. I've written a simple brainfuck interpreter as my first F# program.
What I would like to know:
What is not so relevant:
Obs.: I assume input is always a valid brainfuck code and that's ok to me.
```
open System
open System.IO
let getValue (position:int) (memory:Map) =
match Map.tryFind position memory with
| None -> 0
| value -> value.Value
let calcAccumulator (acc:int) (instruction:char) (search:char) (miss:char) =
match instruction with
| x when x = search -> acc+1
| x when x = miss -> acc-1
| _ -> acc
let rec findMatch (code:string) (search:char) (miss:char) (inc:int) (current:int) (acc:int) =
let instruction = code.[current]
match instruction, acc with
| x, 0 when x = search -> current+1
| _ -> findMatch code search miss inc (current+inc) (calcAccumulator acc instruction search miss)
let updateMemory (instruction:char) (position:int) (memory:Map) =
let oldValue = getValue position memory
let newValue =
match instruction with
| '+' -> oldValue + 1
| '-' -> oldValue - 1
| ',' -> Console.ReadKey().KeyChar |> Convert.ToInt32
| _ -> oldValue
Map.add position newValue memory
let updateOutput (instruction) (value:int) =
if instruction = '.'
then Console.Write ((char) value)
let updatePosition (instruction:char) (position:int) =
match instruction with
| '>' -> position+1
| ' position-1
| _ -> position
let updateIndex (code:string) (index:int) (value:int) =
match code.[index], value with
| '[', 0 -> findMatch code ']' '[' 1 (index+1) 0
| ']', x when x <> 0 -> fin
What I would like to know:
- Am I using the right data structure for each situation?
- Is my code easy to understand?
- Is my code style similar to common F# codes (naming, organization etc)?
- Is my code "very declarative" or I'm still thinking in the imperative way?
What is not so relevant:
- Performance (but if I've made something very bad, let me now!)
- More features
Obs.: I assume input is always a valid brainfuck code and that's ok to me.
```
open System
open System.IO
let getValue (position:int) (memory:Map) =
match Map.tryFind position memory with
| None -> 0
| value -> value.Value
let calcAccumulator (acc:int) (instruction:char) (search:char) (miss:char) =
match instruction with
| x when x = search -> acc+1
| x when x = miss -> acc-1
| _ -> acc
let rec findMatch (code:string) (search:char) (miss:char) (inc:int) (current:int) (acc:int) =
let instruction = code.[current]
match instruction, acc with
| x, 0 when x = search -> current+1
| _ -> findMatch code search miss inc (current+inc) (calcAccumulator acc instruction search miss)
let updateMemory (instruction:char) (position:int) (memory:Map) =
let oldValue = getValue position memory
let newValue =
match instruction with
| '+' -> oldValue + 1
| '-' -> oldValue - 1
| ',' -> Console.ReadKey().KeyChar |> Convert.ToInt32
| _ -> oldValue
Map.add position newValue memory
let updateOutput (instruction) (value:int) =
if instruction = '.'
then Console.Write ((char) value)
let updatePosition (instruction:char) (position:int) =
match instruction with
| '>' -> position+1
| ' position-1
| _ -> position
let updateIndex (code:string) (index:int) (value:int) =
match code.[index], value with
| '[', 0 -> findMatch code ']' '[' 1 (index+1) 0
| ']', x when x <> 0 -> fin
Solution
Let me make a few comments:
-
F# has a good system of type inference. You don't need to specify the type explicitly, the compiler in many cases will do it for you. You can read more about it here.
-
In function
Although you can rewrite this code with using defaultArg
-
In function
-
The helper functions better write as nested:
You can read more about it here
-
In function
-
F# has a good system of type inference. You don't need to specify the type explicitly, the compiler in many cases will do it for you. You can read more about it here.
-
In function
getValue. Usually, matched with None|Some value:match Map.tryFind position memory with
| None -> 0
| Some value -> valueAlthough you can rewrite this code with using defaultArg
let getValue position memory =
defaultArg (Map.tryFind position memory) 0-
In function
updateIndex you can check the value with 0 in match:let updateIndex (code:string) index value =
match code.[index], value = 0 with
| '[', true -> findMatch code ']' '[' 1 (index + 1) 0
| ']', false -> findMatch code '[' ']' -1 (index - 1) 0
| _ -> index + 1-
The helper functions better write as nested:
let interpret (code:string) =
let rec interpretHelper index memory position =You can read more about it here
-
In function
interpretHelper, use if-then-else instead of PM:let rec interpretHelper index memory position =
if code |> String.length = index then
memory
else ...Code Snippets
match Map.tryFind position memory with
| None -> 0
| Some value -> valuelet getValue position memory =
defaultArg (Map.tryFind position memory) 0let updateIndex (code:string) index value =
match code.[index], value = 0 with
| '[', true -> findMatch code ']' '[' 1 (index + 1) 0
| ']', false -> findMatch code '[' ']' -1 (index - 1) 0
| _ -> index + 1let interpret (code:string) =
let rec interpretHelper index memory position =let rec interpretHelper index memory position =
if code |> String.length = index then
memory
else ...Context
StackExchange Code Review Q#126408, answer score: 6
Revisions (0)
No revisions yet.