module SimpleNoun where import ClassyPrelude import Numeric.Natural import qualified Urbit.Noun as N type Atom = Natural type Noun = Tree Atom data Tree a = A !a | C !(Tree a) !(Tree a) deriving (Eq, Ord, Read, Functor, Generic) instance Hashable a => Hashable (Tree a) data Fern a = FernA !a | FernF [Fern a] toFern :: Tree a -> Fern a toFern = \case A a -> FernA a C h t -> case toFern t of a@FernA{} -> FernF [toFern h, a] FernF fs -> FernF (toFern h : fs) instance Show a => Show (Fern a) where show = \case FernA a -> show a FernF xs -> "[" <> intercalate " " (map show xs) <> "]" instance Show a => Show (Tree a) where show = show . toFern yes, no :: Noun yes = A 0 no = A 1 loob :: Bool -> Noun loob = \case True -> yes False -> no textToAtom :: Text -> Atom textToAtom t = case N.textToUtf8Atom t of N.A a -> a N.C _ _ -> error "textToAtom: nani!?" showA :: Atom -> String showA a = show (N.A a) tshowA :: Atom -> Text tshowA = pack . showA -- | Tree address type Axis = Atom data Dir = L | R deriving (Eq, Ord, Enum, Read, Show) type Path = [Dir] -- some stuff from hoon.hoon cap :: Axis -> Dir cap = \case 2 -> L 3 -> R a | a <= 1 -> error "cap: bad axis" | otherwise -> cap (div a 2) mas :: Axis -> Axis mas = \case 2 -> 1 3 -> 1 a | a <= 1 -> error "mas: bad axis" | otherwise -> (mod a 2) + 2 * mas (div a 2) capMas :: Axis -> (Dir, Axis) capMas = \case 2 -> (L, 1) 3 -> (R, 1) a | a <= 1 -> error "capMas: bad axis" | otherwise -> (d, (mod a 2) + 2 * r) where (d, r) = capMas (div a 2) peg :: Axis -> Axis -> Axis peg a = \case 1 -> a 2 -> a * 2 3 -> a * 2 + 1 b -> (mod b 2) + 2 * peg a (div b 2) axis :: Axis -> Tree a -> Tree a axis 1 n = n axis (capMas -> (d, r)) (C n m) = case d of L -> axis r n R -> axis r m axis a _ = error ("bad axis: " ++ show a) edit :: Axis -> Tree a -> Tree a -> Tree a edit 1 v n = v edit (capMas -> (d, r)) v (C n m) = case d of L -> C (edit r v n) m R -> C n (edit r v m) edit a _ _ = error ("bad edit: " ++ show a) -- Write an axis as a binary number; e.g. 5 as 101. -- The rule is: after droping the 1 in the msb, you read from left to right. -- 0 becomes L and 1 becomes R. So 5 becomes [L,R] toPath :: Axis -> Path toPath = \case 1 -> [] (capMas -> (d, r)) -> d : toPath r toAxis :: Path -> Axis toAxis = foldl' step 1 where step r = \case L -> 2 * r R -> 2 * r + 1