2019-07-22 02:33:26 +03:00
|
|
|
{-# OPTIONS_GHC -Wwarn #-}
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
module Noun.Conversions
|
2019-07-17 08:32:36 +03:00
|
|
|
( Nullable(..), Jammed(..), AtomCell(..)
|
|
|
|
, Word128, Word256, Word512
|
2019-07-22 21:10:27 +03:00
|
|
|
, Octs(..)
|
2019-07-20 02:18:58 +03:00
|
|
|
, Cord(..), Knot(..), Term(..), Tape(..), Tour(..)
|
2019-07-17 08:32:36 +03:00
|
|
|
, Tank(..), Tang, Plum(..)
|
2019-07-19 03:52:53 +03:00
|
|
|
, Mug(..), Path(..), Ship(..)
|
2019-07-21 22:56:18 +03:00
|
|
|
, Lenient(..)
|
2019-07-12 04:16:40 +03:00
|
|
|
) where
|
|
|
|
|
|
|
|
import ClassyPrelude hiding (hash)
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
import Control.Lens hiding (Index)
|
2019-07-12 04:16:40 +03:00
|
|
|
import Data.Void
|
|
|
|
import Data.Word
|
|
|
|
import Noun.Atom
|
|
|
|
import Noun.Convert
|
|
|
|
import Noun.Core
|
|
|
|
import Noun.TH
|
2019-07-22 21:10:27 +03:00
|
|
|
import Text.Regex.TDFA
|
|
|
|
import Text.Regex.TDFA.Text ()
|
2019-07-12 04:16:40 +03:00
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
import Data.LargeWord (LargeKey, Word128, Word256)
|
|
|
|
import GHC.Natural (Natural)
|
|
|
|
import Noun.Cue (cue)
|
|
|
|
import Noun.Jam (jam)
|
|
|
|
import RIO (decodeUtf8Lenient)
|
|
|
|
import System.IO.Unsafe (unsafePerformIO)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
import qualified Data.Char as C
|
|
|
|
import qualified Data.Text.Encoding as T
|
|
|
|
import qualified Data.Text.Encoding.Error as T
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Noun ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun Noun where
|
|
|
|
toNoun = id
|
|
|
|
|
|
|
|
instance FromNoun Noun where
|
2019-07-22 21:10:27 +03:00
|
|
|
parseNoun = pure
|
|
|
|
|
|
|
|
|
|
|
|
--- Atom -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun Atom where
|
|
|
|
toNoun = Atom
|
|
|
|
|
|
|
|
instance FromNoun Atom where
|
|
|
|
parseNoun = named "Atom" . \case
|
|
|
|
Atom a -> pure a
|
|
|
|
Cell _ _ -> fail "Expecting an atom, but got a cell"
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Void ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun Void where
|
|
|
|
toNoun = absurd
|
|
|
|
|
|
|
|
instance FromNoun Void where
|
2019-07-20 02:18:58 +03:00
|
|
|
parseNoun _ = named "Void" $ fail "Can't produce void"
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
-- Cord ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
newtype Cord = Cord { unCord :: Text }
|
|
|
|
deriving newtype (Eq, Ord, Show, IsString, NFData)
|
|
|
|
|
|
|
|
instance ToNoun Cord where
|
|
|
|
toNoun = textToUtf8Atom . unCord
|
|
|
|
|
|
|
|
instance FromNoun Cord where
|
|
|
|
parseNoun = named "Cord" . fmap Cord . parseNounUtf8Atom
|
|
|
|
|
|
|
|
|
|
|
|
-- Char ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
decodeUtf32LE' :: ByteString -> Either T.UnicodeException Text
|
|
|
|
decodeUtf32LE' =
|
|
|
|
unsafePerformIO . try . evaluate . T.decodeUtf32LEWith T.strictDecode
|
|
|
|
|
|
|
|
instance ToNoun Char where
|
|
|
|
toNoun = Atom . view (from atomBytes) . T.encodeUtf32LE . pack . singleton
|
|
|
|
|
|
|
|
instance FromNoun Char where
|
|
|
|
parseNoun n = named "Char" $ do
|
|
|
|
a :: Atom <- parseNoun n
|
|
|
|
fmap unpack (decodeUtf32LE' (a ^. atomBytes)) & \case
|
|
|
|
Left err -> fail (show err)
|
|
|
|
Right [] -> pure '\0'
|
|
|
|
Right [c] -> pure c
|
|
|
|
Right cs -> fail ("Expecting a character, but got string: " <> cs)
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
-- Tour ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
newtype Tour = Tour [Char]
|
2019-07-20 02:18:58 +03:00
|
|
|
deriving newtype (Eq, Ord, Show, ToNoun, FromNoun)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
2019-07-17 08:32:36 +03:00
|
|
|
-- Double Jammed ---------------------------------------------------------------
|
|
|
|
|
|
|
|
newtype Jammed a = Jammed a
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
instance ToNoun a => ToNoun (Jammed a) where
|
|
|
|
toNoun (Jammed a) = Atom $ jam $ toNoun a
|
|
|
|
|
|
|
|
instance FromNoun a => FromNoun (Jammed a) where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "Jammed" $ do
|
2019-07-17 08:32:36 +03:00
|
|
|
a <- parseNoun n
|
|
|
|
cue a & \case
|
|
|
|
Left err -> fail (show err)
|
|
|
|
Right res -> do
|
|
|
|
Jammed <$> parseNoun res
|
|
|
|
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
-- Atom or Cell ----------------------------------------------------------------
|
|
|
|
|
2019-07-16 03:01:45 +03:00
|
|
|
type Word512 = LargeKey Word256 Word256
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
data AtomCell a c
|
|
|
|
= ACAtom a
|
|
|
|
| ACCell c
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun c) => ToNoun (AtomCell a c) where
|
|
|
|
toNoun (ACAtom a) = toNoun a
|
|
|
|
toNoun (ACCell c) = toNoun c
|
|
|
|
|
|
|
|
instance (FromNoun a, FromNoun c) => FromNoun (AtomCell a c) where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,)" $ case n of
|
|
|
|
Atom _ -> ACAtom <$> parseNoun n
|
|
|
|
Cell _ _ -> ACCell <$> parseNoun n
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
2019-07-21 22:56:18 +03:00
|
|
|
-- Lenient ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
data Lenient a
|
|
|
|
= FailParse Noun
|
|
|
|
| GoodParse a
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
instance FromNoun a => FromNoun (Lenient a) where
|
|
|
|
parseNoun n =
|
2019-07-22 02:33:26 +03:00
|
|
|
(GoodParse <$> parseNoun n) <|> fallback
|
|
|
|
where
|
|
|
|
fallback =
|
|
|
|
fromNounErr n & \case
|
|
|
|
Right x -> pure (GoodParse x)
|
|
|
|
Left err -> do
|
|
|
|
traceM ("LENIENT.FromNoun: " <> show err)
|
|
|
|
pure (FailParse n)
|
2019-07-21 22:56:18 +03:00
|
|
|
|
|
|
|
instance ToNoun a => ToNoun (Lenient a) where
|
2019-07-22 02:33:26 +03:00
|
|
|
toNoun (FailParse n) = trace ("LENIENT.ToNoun: " <> show n)
|
|
|
|
n
|
2019-07-21 22:56:18 +03:00
|
|
|
toNoun (GoodParse x) = toNoun x
|
|
|
|
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
-- Nullable --------------------------------------------------------------------
|
|
|
|
|
|
|
|
{-|
|
|
|
|
`Nullable a <-> ?@(~ a)`
|
|
|
|
|
|
|
|
This is distinct from `unit`, since there is no tag on the non-atom
|
|
|
|
case, therefore `a` must always be cell type.
|
|
|
|
-}
|
2019-07-21 07:13:21 +03:00
|
|
|
data Nullable a = None | Some a
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
instance ToNoun a => ToNoun (Nullable a) where
|
|
|
|
toNoun = toNoun . \case None -> ACAtom ()
|
|
|
|
Some x -> ACCell x
|
|
|
|
|
|
|
|
instance FromNoun a => FromNoun (Nullable a) where
|
|
|
|
parseNoun n = named "Nullable" $ do
|
|
|
|
parseNoun n >>= \case
|
|
|
|
(ACAtom ()) -> pure None
|
|
|
|
(ACCell x) -> pure (Some x)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- List ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun a => ToNoun [a] where
|
|
|
|
toNoun xs = nounFromList (toNoun <$> xs)
|
|
|
|
where
|
|
|
|
nounFromList :: [Noun] -> Noun
|
|
|
|
nounFromList [] = Atom 0
|
|
|
|
nounFromList (x:xs) = Cell x (nounFromList xs)
|
|
|
|
|
|
|
|
instance FromNoun a => FromNoun [a] where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun = named "[]" . \case
|
|
|
|
Atom 0 -> pure []
|
|
|
|
Atom _ -> fail "list terminated with non-null atom"
|
|
|
|
Cell l r -> (:) <$> parseNoun l <*> parseNoun r
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Tape ------------------------------------------------------------------------
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
{-
|
|
|
|
A `tape` is a list of utf8 bytes.
|
|
|
|
-}
|
|
|
|
newtype Tape = Tape { unTape :: Text }
|
|
|
|
deriving newtype (Eq, Ord, Show, Semigroup, Monoid, IsString)
|
|
|
|
|
|
|
|
instance ToNoun Tape where
|
|
|
|
toNoun = toNoun . (unpack :: ByteString -> [Word8]) . encodeUtf8 . unTape
|
|
|
|
|
|
|
|
instance FromNoun Tape where
|
|
|
|
parseNoun n = named "Tape" $ do
|
|
|
|
as :: [Word8] <- parseNoun n
|
|
|
|
T.decodeUtf8' (pack as) & \case
|
|
|
|
Left err -> fail (show err)
|
|
|
|
Right tx -> pure (Tape tx)
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Pretty Printing -------------------------------------------------------------
|
|
|
|
|
|
|
|
type Tang = [Tank]
|
|
|
|
|
2019-07-16 03:01:45 +03:00
|
|
|
data Tank
|
|
|
|
= Leaf Tape
|
|
|
|
| Plum Plum
|
2019-07-12 04:16:40 +03:00
|
|
|
| Palm (Tape, Tape, Tape, Tape) [Tank]
|
|
|
|
| Rose (Tape, Tape, Tape) [Tank]
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
data WideFmt = WideFmt { delimit :: Cord, enclose :: Maybe (Cord, Cord) }
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
data TallFmt = TallFmt { intro :: Cord, indef :: Maybe (Cord, Cord) }
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
data PlumFmt = PlumFmt (Maybe WideFmt) (Maybe TallFmt)
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
type Plum = AtomCell Cord PlumTree
|
|
|
|
|
|
|
|
data PlumTree
|
|
|
|
= Para Cord [Cord]
|
|
|
|
| Tree PlumFmt [Plum]
|
|
|
|
| Sbrk Plum
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
|
|
deriveNoun ''WideFmt
|
|
|
|
deriveNoun ''TallFmt
|
|
|
|
deriveNoun ''PlumFmt
|
2019-07-16 03:01:45 +03:00
|
|
|
deriveNoun ''Tank
|
2019-07-12 04:16:40 +03:00
|
|
|
deriveNoun ''PlumTree
|
|
|
|
|
|
|
|
|
|
|
|
-- ByteString ------------------------------------------------------------------
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
newtype Octs = Octs { unOcts :: ByteString }
|
|
|
|
deriving newtype (Eq, Ord, Show)
|
|
|
|
|
|
|
|
instance ToNoun Octs where
|
|
|
|
toNoun (Octs bs) =
|
|
|
|
toNoun (int2Word (length bs), bs ^. from atomBytes)
|
2019-07-12 04:16:40 +03:00
|
|
|
where
|
|
|
|
int2Word :: Int -> Word
|
|
|
|
int2Word = fromIntegral
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
instance FromNoun Octs where
|
|
|
|
parseNoun x = named "Octs" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(word2Int -> len, atom) <- parseNoun x
|
|
|
|
let bs = atom ^. atomBytes
|
2019-07-22 21:10:27 +03:00
|
|
|
pure $ Octs $ case compare (length bs) len of
|
2019-07-12 04:16:40 +03:00
|
|
|
EQ -> bs
|
|
|
|
LT -> bs <> replicate (len - length bs) 0
|
|
|
|
GT -> take len bs
|
|
|
|
where
|
|
|
|
word2Int :: Word -> Int
|
|
|
|
word2Int = fromIntegral
|
|
|
|
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
-- Knot ------------------------------------------------------------------------
|
2019-07-12 04:16:40 +03:00
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
{-
|
|
|
|
Knot (@ta) is an array of Word8 encoding an ASCII string.
|
|
|
|
-}
|
|
|
|
newtype Knot = MkKnot { unKnot :: Text }
|
|
|
|
deriving newtype (Eq, Ord, Show, Semigroup, Monoid, IsString)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
instance ToNoun Knot where
|
|
|
|
toNoun = textToUtf8Atom . unKnot
|
|
|
|
|
|
|
|
instance FromNoun Knot where
|
|
|
|
parseNoun n = named "Knot" $ do
|
|
|
|
txt <- parseNounUtf8Atom n
|
|
|
|
if all C.isAscii txt
|
|
|
|
then pure (MkKnot txt)
|
|
|
|
else fail ("Non-ASCII chars in knot: " <> unpack txt)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Term ------------------------------------------------------------------------
|
|
|
|
|
2019-07-22 21:10:27 +03:00
|
|
|
{-
|
|
|
|
A Term (@tas) is a Knot satisfying the regular expression:
|
|
|
|
|
|
|
|
([a-z][a-z0-9]*(-[a-z0-9]+)*)?
|
|
|
|
-}
|
|
|
|
newtype Term = MkTerm { unTerm :: Text }
|
|
|
|
deriving newtype (Eq, Ord, Show, Semigroup, Monoid, IsString)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
instance ToNoun Term where -- XX TODO
|
2019-07-22 21:10:27 +03:00
|
|
|
toNoun = textToUtf8Atom . unTerm
|
|
|
|
|
|
|
|
knotRegex :: Text
|
|
|
|
knotRegex = "([a-z][a-z0-9]*(-[a-z0-9]+)*)?"
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
instance FromNoun Term where -- XX TODO
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "Term" $ do
|
2019-07-22 21:10:27 +03:00
|
|
|
MkKnot t <- parseNoun n
|
|
|
|
if t =~ knotRegex
|
|
|
|
then pure (MkTerm t)
|
|
|
|
else fail ("Term not valid symbol: " <> unpack t)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
2019-07-19 03:52:53 +03:00
|
|
|
-- Ship ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
newtype Ship = Ship Word128 -- @p
|
|
|
|
deriving newtype (Eq, Ord, Show, Num, ToNoun, FromNoun)
|
|
|
|
|
|
|
|
|
2019-07-16 03:01:45 +03:00
|
|
|
-- Path ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
newtype Path = Path [Knot]
|
2019-07-21 07:13:21 +03:00
|
|
|
deriving newtype (Eq, Ord, Semigroup, Monoid)
|
2019-07-16 03:01:45 +03:00
|
|
|
|
|
|
|
instance Show Path where
|
|
|
|
show (Path ks) = show $ intercalate "/" ("" : ks)
|
|
|
|
|
|
|
|
|
|
|
|
-- Mug -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
newtype Mug = Mug Word32
|
|
|
|
deriving newtype (Eq, Ord, Show, Num, ToNoun, FromNoun)
|
|
|
|
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
-- Bool ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun Bool where
|
|
|
|
toNoun True = Atom 0
|
|
|
|
toNoun False = Atom 1
|
|
|
|
|
|
|
|
instance FromNoun Bool where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun = named "Bool" . parse
|
|
|
|
where
|
|
|
|
parse n =
|
|
|
|
parseNoun n >>= \case
|
2019-07-21 02:47:35 +03:00
|
|
|
(0::Atom) -> pure True
|
|
|
|
1 -> pure False
|
2019-07-19 21:37:20 +03:00
|
|
|
_ -> fail "Atom is not a valid loobean"
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Integer ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun Integer where
|
|
|
|
toNoun = toNoun . (fromIntegral :: Integer -> Natural)
|
|
|
|
|
|
|
|
instance FromNoun Integer where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun = named "Integer" . fmap natInt . parseNoun
|
|
|
|
where
|
|
|
|
natInt :: Natural -> Integer
|
|
|
|
natInt = fromIntegral
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Words -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
atomToWord :: forall a. (Bounded a, Integral a) => Atom -> Parser a
|
|
|
|
atomToWord atom = do
|
|
|
|
if atom > fromIntegral (maxBound :: a)
|
|
|
|
then fail "Atom doesn't fit in fixed-size word"
|
|
|
|
else pure (fromIntegral atom)
|
|
|
|
|
|
|
|
wordToNoun :: Integral a => a -> Noun
|
|
|
|
wordToNoun = Atom . fromIntegral
|
|
|
|
|
|
|
|
nounToWord :: forall a. (Bounded a, Integral a) => Noun -> Parser a
|
|
|
|
nounToWord = parseNoun >=> atomToWord
|
|
|
|
|
|
|
|
instance ToNoun Word where toNoun = wordToNoun
|
|
|
|
instance ToNoun Word8 where toNoun = wordToNoun
|
|
|
|
instance ToNoun Word16 where toNoun = wordToNoun
|
|
|
|
instance ToNoun Word32 where toNoun = wordToNoun
|
|
|
|
instance ToNoun Word64 where toNoun = wordToNoun
|
2019-07-16 03:01:45 +03:00
|
|
|
instance ToNoun Word128 where toNoun = wordToNoun
|
|
|
|
instance ToNoun Word256 where toNoun = wordToNoun
|
|
|
|
instance ToNoun Word512 where toNoun = wordToNoun
|
2019-07-12 04:16:40 +03:00
|
|
|
|
2019-07-19 21:37:20 +03:00
|
|
|
instance FromNoun Word where parseNoun = named "Word" . nounToWord
|
|
|
|
instance FromNoun Word8 where parseNoun = named "Word8" . nounToWord
|
|
|
|
instance FromNoun Word16 where parseNoun = named "Word16" . nounToWord
|
|
|
|
instance FromNoun Word32 where parseNoun = named "Word32" . nounToWord
|
|
|
|
instance FromNoun Word64 where parseNoun = named "Word64" . nounToWord
|
|
|
|
instance FromNoun Word128 where parseNoun = named "Word128" . nounToWord
|
|
|
|
instance FromNoun Word256 where parseNoun = named "Word256" . nounToWord
|
|
|
|
instance FromNoun Word512 where parseNoun = named "Word512" . nounToWord
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Maybe is `unit` -------------------------------------------------------------
|
|
|
|
|
|
|
|
-- TODO Consider enforcing that `a` must be a cell.
|
|
|
|
instance ToNoun a => ToNoun (Maybe a) where
|
|
|
|
toNoun Nothing = Atom 0
|
|
|
|
toNoun (Just x) = Cell (Atom 0) (toNoun x)
|
|
|
|
|
|
|
|
instance FromNoun a => FromNoun (Maybe a) where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun = named "Maybe" . \case
|
2019-07-12 04:16:40 +03:00
|
|
|
Atom 0 -> pure Nothing
|
|
|
|
Atom n -> unexpected ("atom " <> show n)
|
|
|
|
Cell (Atom 0) t -> Just <$> parseNoun t
|
|
|
|
Cell n _ -> unexpected ("cell with head-atom " <> show n)
|
|
|
|
where
|
|
|
|
unexpected s = fail ("Expected unit value, but got " <> s)
|
|
|
|
|
|
|
|
|
2019-07-21 07:13:21 +03:00
|
|
|
-- Either is `each` ------------------------------------------------------------
|
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun b) => ToNoun (Either a b) where
|
|
|
|
toNoun (Left x) = Cell (Atom 0) (toNoun x)
|
|
|
|
toNoun (Right x) = Cell (Atom 1) (toNoun x)
|
|
|
|
|
|
|
|
instance (FromNoun a, FromNoun b) => FromNoun (Either a b) where
|
|
|
|
parseNoun n = named "Either" $ do
|
|
|
|
(Atom tag, v) <- parseNoun n
|
|
|
|
case tag of
|
|
|
|
0 -> named "%|" (Left <$> parseNoun v)
|
|
|
|
1 -> named "%&" (Right <$> parseNoun v)
|
|
|
|
n -> fail ("Each has invalid head-atom: " <> show n)
|
|
|
|
|
|
|
|
|
2019-07-12 04:16:40 +03:00
|
|
|
-- Tuple Conversions -----------------------------------------------------------
|
|
|
|
|
|
|
|
instance ToNoun () where
|
|
|
|
toNoun () = Atom 0
|
|
|
|
|
|
|
|
instance FromNoun () where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun = named "()" . \case
|
|
|
|
Atom 0 -> pure ()
|
|
|
|
x -> fail ("expecting `~`, but got " <> show x)
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun b) => ToNoun (a, b) where
|
|
|
|
toNoun (x, y) = Cell (toNoun x) (toNoun y)
|
|
|
|
|
|
|
|
instance (FromNoun a, FromNoun b) => FromNoun (a, b) where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun = named ("(,)") . \case
|
|
|
|
Atom n -> fail ("expected a cell, but got an atom: " <> show n)
|
|
|
|
Cell l r -> (,) <$> parseNoun l <*> parseNoun r
|
2019-07-12 04:16:40 +03:00
|
|
|
|
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun b, ToNoun c) => ToNoun (a, b, c) where
|
|
|
|
toNoun (x, y, z) = toNoun (x, (y, z))
|
|
|
|
|
|
|
|
instance (FromNoun a, FromNoun b, FromNoun c) => FromNoun (a, b, c) where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(x, t) <- parseNoun n
|
|
|
|
(y, z) <- parseNoun t
|
|
|
|
pure (x, y, z)
|
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d) => ToNoun (a, b, c, d) where
|
|
|
|
toNoun (p, q, r, s) = toNoun (p, (q, r, s))
|
|
|
|
|
|
|
|
instance (FromNoun a, FromNoun b, FromNoun c, FromNoun d)
|
|
|
|
=> FromNoun (a, b, c, d)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s) <- parseNoun tail
|
|
|
|
pure (p, q, r, s)
|
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e)
|
|
|
|
=> ToNoun (a, b, c, d, e) where
|
|
|
|
toNoun (p, q, r, s, t) = toNoun (p, (q, r, s, t))
|
|
|
|
|
|
|
|
instance (FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e)
|
|
|
|
=> FromNoun (a, b, c, d, e)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,,)"$ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s, t) <- parseNoun tail
|
|
|
|
pure (p, q, r, s, t)
|
|
|
|
|
|
|
|
instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e, ToNoun f)
|
|
|
|
=> ToNoun (a, b, c, d, e, f) where
|
|
|
|
toNoun (p, q, r, s, t, u) = toNoun (p, (q, r, s, t, u))
|
|
|
|
|
|
|
|
instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e
|
|
|
|
, FromNoun f
|
|
|
|
)
|
|
|
|
=> FromNoun (a, b, c, d, e, f)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s, t, u) <- parseNoun tail
|
|
|
|
pure (p, q, r, s, t, u)
|
|
|
|
|
|
|
|
instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e
|
|
|
|
, FromNoun f, FromNoun g
|
|
|
|
)
|
|
|
|
=> FromNoun (a, b, c, d, e, f, g)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,,,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s, t, u, v) <- parseNoun tail
|
|
|
|
pure (p, q, r, s, t, u, v)
|
|
|
|
|
|
|
|
instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e
|
|
|
|
, FromNoun f, FromNoun g, FromNoun h
|
|
|
|
)
|
|
|
|
=> FromNoun (a, b, c, d, e, f, g, h)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,,,,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s, t, u, v, w) <- parseNoun tail
|
|
|
|
pure (p, q, r, s, t, u, v, w)
|
|
|
|
|
|
|
|
instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e
|
|
|
|
, FromNoun f, FromNoun g, FromNoun h, FromNoun i
|
|
|
|
)
|
|
|
|
=> FromNoun (a, b, c, d, e, f, g, h, i)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,,,,,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s, t, u, v, w, x) <- parseNoun tail
|
|
|
|
pure (p, q, r, s, t, u, v, w, x)
|
|
|
|
|
|
|
|
instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e
|
|
|
|
, FromNoun f, FromNoun g, FromNoun h, FromNoun i, FromNoun j
|
|
|
|
)
|
|
|
|
=> FromNoun (a, b, c, d, e, f, g, h, i, j)
|
|
|
|
where
|
2019-07-19 21:37:20 +03:00
|
|
|
parseNoun n = named "(,,,,,,,,,)" $ do
|
2019-07-12 04:16:40 +03:00
|
|
|
(p, tail) <- parseNoun n
|
|
|
|
(q, r, s, t, u, v, w, x, y) <- parseNoun tail
|
|
|
|
pure (p, q, r, s, t, u, v, w, x, y)
|
2019-07-21 07:13:21 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Derived Instances -----------------------------------------------------------
|
|
|
|
|
|
|
|
deriveNoun ''Path
|