I'm a beginner to Haskell and functional programming as a whole and as a first project I've written a Brain-Flak implementation in Haskell.
I wanted to get some feedback on this implementation because I've never done anything this big in a functional programming language. Is my code two iterative? What could make this better Haskell? I found pattern matching very useful, am I using it too much?
BrainHack:
Currently I don't have any fancy IO for this program, just a function that can be called with ghci. The relevant function here is brainflak it takes a String as source and a [Integer] as input to the Brain-Flak. It is really just a wrapper around the function bf that uses balanced to first check if the Brain-Flak code is syntactically valid. bf does most of the computation using pattern matching and the Three Stack Model of Brain Flak.
-- pop is a head that defaults to zero
pop :: (Integral a) => [a] -> a
pop [] = 0
pop (x:_) = x
-- rest is a tail for pop
rest :: (Integral a) => [a] -> [a]
rest [] = []
rest (_:x) = x
-- topadd adds an Integer to the top of a [Integer]
topadd :: [Integer] -> Integer -> [Integer]
topadd [] x = [x]
topadd (a:[]) x = [a+x]
topadd (a:b) x = (a+x):b
-- ir is a helper function of interior
ir :: String -> Integer -> String
ir x 0 = ""
ir ('{':x) y = "{" ++ (ir x (y+1))
ir ('}':x) y = "}" ++ (ir x (y-1))
ir (a:x) y = [a] ++ (ir x y )
-- interior finds the inside of a loop {x}... -> x
interior :: String -> String
interior x = init (ir x 1)
-- ex is a helper function for exterior
ex :: String -> Integer -> String
ex x 0 = x
ex ('{':x) y = ex x (y+1)
ex ('}':x) y = ex x (y-1)
ex (a:x) y = ex x y
-- exterior finds all the code after a loop {...}x -> x
exterior :: String -> String
exterior x = ex x 1
-- bf is the implementation of brain-flak
bf :: String -> ([Integer],[Integer],[Integer]) -> ([Integer],[Integer],[Integer])
bf [] (x,y,z)= (x,y,z)
bf ('(':')':a) (x,y,z)= bf a (x,y,((pop z+1):rest z))
bf ('<':'>':a) (x,y,z)= bf a (y,x,z)
bf ('{':'}':a) (x,y,z)= bf a ((rest x),y,(topadd z (pop x)))
bf ('[':']':a) (x,y,z)= bf a (x,y,(topadd z (toInteger (length x))))
bf ('(':a) (x,y,z)= bf a (x,y,(0:z))
bf ('<':a) (x,y,z)= bf a (x,y,(0:z))
bf ('[':a) (x,y,z)= bf a (x,y,(0:z))
bf (')':a) (x,y,(h:z))= bf a ((h:x),y,(topadd z h))
bf (']':a) (x,y,(h:z))= bf a (x,y,(topadd z (-h)))
bf ('>':a) (x,y,(_:z))= bf a (x,y,z)
bf ('{':a) t = bf (exterior a) (loop (interior a) t)
bf (_:a) t = bf a t
-- loop runs the same code until the TOS is zero
loop :: String -> ([Integer],[Integer],[Integer]) -> ([Integer],[Integer],[Integer])
loop s ([],y,z) = ([],y,z)
loop s (0:x,y,z) = (0:x,y,z)
loop s x = loop s (bf s x)
-- bl is an helper function of balance
bl :: String -> String -> Bool
bl [] [] = True
bl [] _ = False
bl ('(':x) y = bl x (')':y)
bl ('[':x) y = bl x (']':y)
bl ('<':x) y = bl x ('>':y)
bl ('{':x) y = bl x ('}':y)
bl _ [] = False
bl (a:x) (b:y) = (a == b) && (bl x y)
-- balanced checks if a particular String is balanced
balanced :: String -> Bool
balanced x = bl x []
-- Implements Brain-Flak
brainflak :: String -> [Integer] -> [Integer]
brainflak s x
| balanced source = (\(a,_,_) -> a) (bf source (x,[],[]))
| otherwise = error "Unbalanced braces."
where source = [a|a <- s, elem a "()[]<>{}"]
[Char]over its arguably more intuitive aliasString? \$\endgroup\$