Initial commit
This commit is contained in:
87
forth.hs
Normal file
87
forth.hs
Normal file
@@ -0,0 +1,87 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
-- This is a WIP solution to
|
||||
-- https://exercism.org/tracks/haskell/exercises/forth
|
||||
|
||||
module Forth (
|
||||
ForthError(..),
|
||||
ForthState,
|
||||
evalText,
|
||||
toList,
|
||||
emptyState
|
||||
) where
|
||||
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Read
|
||||
import Data.Either
|
||||
import Data.Maybe
|
||||
|
||||
data ForthError
|
||||
= DivisionByZero
|
||||
| StackUnderflow
|
||||
| InvalidWord
|
||||
| UnknownWord Text
|
||||
deriving (Show, Eq)
|
||||
|
||||
data ForthState = ForthState [Int]
|
||||
|
||||
instance Show ForthState where
|
||||
show (ForthState stack) = "ForthState " ++ show stack
|
||||
|
||||
emptyState :: ForthState
|
||||
emptyState = ForthState []
|
||||
|
||||
-- Your evaluator has to support the following words:
|
||||
-- +, -, *, / (integer arithmetic)
|
||||
-- DUP, DROP, SWAP, OVER (stack manipulation)
|
||||
evalText :: Text -> ForthState -> Either ForthError ForthState
|
||||
evalText text =
|
||||
case text of
|
||||
"/" -> forthOp div
|
||||
"+" -> forthOp (+)
|
||||
"-" -> forthOp (-)
|
||||
"*" -> forthOp (*)
|
||||
"DUP" -> forthDup
|
||||
"DROP" -> forthDrop
|
||||
"SWAP" -> forthSwap
|
||||
"OVER" -> forthOver
|
||||
otherwise -> appendAsNum
|
||||
where
|
||||
appendAsNum =
|
||||
case decimal text of
|
||||
Right v -> forthAppend $ fst v
|
||||
Left _ -> \_ -> Left $ UnknownWord text
|
||||
|
||||
-- Pop a, b from stack, apply `op` to them and push the result on top.
|
||||
forthOp :: (Int -> Int -> Int) -> ForthState -> Either ForthError ForthState
|
||||
forthOp op (ForthState (x1:x2:xs)) = Right $ ForthState (op x1 x2:xs)
|
||||
forthOp op _ = Left StackUnderflow
|
||||
|
||||
-- Duplicate the stack head
|
||||
forthDup :: ForthState -> Either ForthError ForthState
|
||||
forthDup (ForthState (x:xs)) = Right $ ForthState (x:x:xs)
|
||||
forthDup _ = Left StackUnderflow
|
||||
|
||||
-- Discard the stack head
|
||||
forthDrop :: ForthState -> Either ForthError ForthState
|
||||
forthDrop (ForthState (_:xs)) = Right $ ForthState xs
|
||||
forthDrop _ = Left StackUnderflow
|
||||
|
||||
-- Swap the top two elements of the stack.
|
||||
forthSwap :: ForthState -> Either ForthError ForthState
|
||||
forthSwap (ForthState (xa:xb:xs)) = Right $ ForthState (xb:xa:xs)
|
||||
forthSwap _ = Left StackUnderflow
|
||||
|
||||
-- Copy second item to top
|
||||
forthOver :: ForthState -> Either ForthError ForthState
|
||||
forthOver (ForthState (x1:x2:xs)) = Right $ ForthState (x2:x1:x2:xs)
|
||||
forthOver _ = Left StackUnderflow
|
||||
|
||||
-- Add v to the top of the stack
|
||||
forthAppend :: Int -> ForthState -> Either ForthError ForthState
|
||||
forthAppend v (ForthState (x:xs)) = Right $ ForthState (v:x:xs)
|
||||
|
||||
toList :: ForthState -> [Int]
|
||||
toList (ForthState stack) = stack
|
||||
|
||||
Reference in New Issue
Block a user