packages feed

co-feldspar-0.1.0.1: src/Data/Struct.hs

{-# language GADTs #-}
{-# language ConstraintKinds #-}
{-# language ScopedTypeVariables #-}
{-# language Rank2Types #-}
{-# language StandaloneDeriving #-}

module Data.Struct where

import Control.Monad.Identity

--------------------------------------------------------------------------------
-- * Representation.
--------------------------------------------------------------------------------

-- | Typed binary tree structure
data Struct pred con a
  where
    Node   :: pred a => con a -> Struct pred con a
    Branch :: Struct pred con a -> Struct pred con b -> Struct pred con (a, b)

extractNode :: pred a => Struct pred con a -> con a
extractNode (Node a) = a

--------------------------------------------------------------------------------

toStruct :: Struct pred con a -> a -> Struct pred Identity a
toStruct rep = go rep . Identity
  where
    go :: Struct pred con a -> Identity a -> Struct pred Identity a
    go (Node _) i = Node i
    go (Branch u v) (Identity (a, b)) = Branch (go u (Identity a)) (go v (Identity b))

listStruct :: forall pred cont b c . (forall y . pred y => cont y -> c) -> Struct pred cont b -> [c]
listStruct f = go
  where
    go :: Struct pred cont a -> [c]
    go (Node a)     = [f a]
    go (Branch u v) = go u ++ go v

liftStruct
  :: (pred a, pred b)
  => (con a -> con b)
  -> Struct pred con a
  -> Struct pred con b
liftStruct f (Node a) = Node (f a)

liftStruct2
  :: (pred a, pred b, pred c)
  => (con a -> con b -> con c)
  -> Struct pred con a
  -> Struct pred con b
  -> Struct pred con c
liftStruct2 f (Node a) (Node b) = Node (f a b)

--------------------------------------------------------------------------------
-- ** Operations

-- | Map over a `Struct`.
mapStruct :: forall pred c1 c2 b
  .  (forall a. pred a => c1 a -> c2 a)
  -> Struct pred c1 b
  -> Struct pred c2 b
mapStruct f = go
  where
    go :: Struct pred c1 a -> Struct pred c2 a
    go (Node a) = Node (f a)
    go (Branch a b) = Branch (go a) (go b)

-- | Monadic map over a `Struct`.
mapStructA :: forall m pred c1 c2 b
  .  Applicative m
  => (forall a. pred a => c1 a -> m (c2 a))
  -> Struct pred c1 b
  -> m (Struct pred c2 b)
mapStructA f = go
  where
    go :: Struct pred c1 a -> m (Struct pred c2 a)
    go (Node a) = Node <$> f a
    go (Branch a b) = Branch <$> go a <*> go b

-- | Zip two 'Struct's to a list.
zipListStruct :: forall pred c1 c2 b r
    . (forall a . pred a => c1 a -> c2 a -> r)
    -> Struct pred c1 b
    -> Struct pred c2 b
    -> [r]
zipListStruct f = go
  where
    go :: Struct pred c1 a -> Struct pred c2 a -> [r]
    go (Node a)     (Node b)     = [f a b]
    go (Branch a b) (Branch c d) = go a c ++ go b d

--------------------------------------------------------------------------------