hsnock-0.5.0: Language/Nock5K/Spec.hs
module Language.Nock5K.Spec where
import Control.Monad.Instances
-- * Structures
{-| #spec-l3#
A noun is an atom or a cell. An atom is any natural number.
A cell is an ordered pair of nouns.
-}
data Noun = Atom !Integer | !Noun :- !Noun deriving (Eq)
-- | Monad representing either a computed result or an error message.
type Nock = Either String
-- * Reductions
nock, wut, lus, tis, fas, tar :: Noun -> Nock Noun
{-| #spec-l8#
@
nock(a) *a
@-}
nock = tar
{- spec-l9
[a b c] [a [b c]]
-}
infixr 1 :-
{-| #spec-l11#
@
?[a b] 0
?a 1
@-}
wut (a :- b) = return $ Atom 0
wut a = return $ Atom 1
{-| #spec-l13#
@
+[a b] +[a b]
+a 1 + a
@-}
lus (a :- b) = Left "+[a b]"
lus (Atom a) = return $ Atom (1 + a)
{-| #spec-l15#
@
=[a a] 0
=[a b] 1
=a =a
@-}
tis (a :- a') | a == a' = return $ Atom 0
tis (a :- b) = return $ Atom 1
tis a = Left "=a"
{-| #spec-l19#
@
\/[1 a] a
\/[2 a b] a
\/[3 a b] b
\/[(a + a) b] \/[2 \/[a b]]
\/[(a + a + 1) b] \/[3 \/[a b]]
\/a \/a
@-}
fas (Atom 1 :- a) = return a
fas (Atom 2 :- a :- b) = return a
fas (Atom 3 :- a :- b) = return b
fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
fas $ Atom (2 + (a `mod` 2)) :- x
fas a = Left "/a"
{-| #spec-l26#
@
\*[a [b c] d] [\*[a b c] \*[a d]]
\ \*[a 0 b] \/[b a]
\*[a 1 b] b
\*[a 2 b c] \*[\*[a b] \*[a c]]
\*[a 3 b] ?\*[a b]
\*[a 4 b] +\*[a b]
\*[a 5 b] =\*[a b]
\ \*[a 6 b c d] \*[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
\*[a 7 b c] \*[a 2 b 1 c]
\*[a 8 b c] \*[a 7 [[7 [0 1] b] 0 1] c]
\*[a 9 b c] \*[a 7 c 2 [0 1] 0 b]
\*[a 10 [b c] d] \*[a 8 c 7 [0 3] d]
\*[a 10 b c] \*[a c]
\ \*a \*a
@-}
tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
y <- tar (a :- d)
return $ x :- y
tar (a :- Atom 0 :- b) = fas $ b :- a
tar (a :- Atom 1 :- b) = return b
tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
y <- tar (a :- c)
tar $ x :- y
tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
Atom 2 :- (Atom 1 :- c :- d) :-
(Atom 1 :- Atom 0) :- Atom 2 :-
(Atom 1 :- Atom 2 :- Atom 3) :-
(Atom 1 :- Atom 0) :- Atom 4 :-
Atom 4 :- b)
tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
Atom 0 :- Atom 1) :- c)
tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
(Atom 0 :- Atom 1) :- Atom 0 :- b)
tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
(Atom 0 :- Atom 3) :- d)
tar (a :- Atom 10 :- b :- c) = tar (a :- c)
tar a = Left "*a"