moonlight-core-0.1.0.0: src-syntax/Moonlight/Core/Language.hs
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE TypeFamilies #-}
module Moonlight.Core.Language
( ZipMatch (..),
Language,
sameNodeShape,
zipSameNodeShape,
HasConstructorTag (..),
)
where
import Data.Foldable (toList)
import Data.Functor (void)
import Data.Kind (Constraint, Type)
import Data.Traversable (mapAccumL)
import Prelude (Bool, Maybe (Just, Nothing), Ord, Traversable, otherwise, sequenceA, (==))
type ZipMatch :: (Type -> Type) -> Constraint
-- | Structural one-layer matching. @zipMatch@ succeeds iff the two nodes have the same shape, aligning children positionally and pairing every child.
class Traversable f => ZipMatch f where
zipMatch :: f left -> f right -> Maybe (f (left, right))
type Language :: (Type -> Type) -> Constraint
class (Traversable f, forall a. Ord a => Ord (f a)) => Language f
instance (Traversable f, forall a. Ord a => Ord (f a)) => Language f
sameNodeShape :: Language f => f left -> f right -> Bool
sameNodeShape leftNode rightNode =
void leftNode == void rightNode
zipSameNodeShape ::
Language f =>
f left ->
f right ->
Maybe (f (left, right))
zipSameNodeShape leftNode rightNode
| sameNodeShape leftNode rightNode =
case mapAccumL consumeRightChild (toList rightNode) leftNode of
([], zippedNode) ->
sequenceA zippedNode
_ ->
Nothing
| otherwise =
Nothing
where
consumeRightChild ::
[right] ->
left ->
([right], Maybe (left, right))
consumeRightChild rightChildren leftChild =
case rightChildren of
rightChild : trailingRightChildren ->
(trailingRightChildren, Just (leftChild, rightChild))
[] ->
([], Nothing)
type HasConstructorTag :: (Type -> Type) -> Constraint
class (Language f, Ord (ConstructorTag f)) => HasConstructorTag f where
type ConstructorTag f :: Type
constructorTag :: f a -> ConstructorTag f