Skip to content

Commit

Permalink
Merge pull request #32 from frog-da/main
Browse files Browse the repository at this point in the history
Add AST and NameMap helpers
  • Loading branch information
fizruk authored Dec 15, 2024
2 parents 66534e8 + d222c12 commit 65c6297
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
7 changes: 6 additions & 1 deletion haskell/free-foil/src/Control/Monad/Foil/Internal.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
Expand Down Expand Up @@ -808,7 +809,7 @@ instance (Sinkable e) => Sinkable (Substitution e i) where
-- * 'Name' maps

-- | A /total/ map from names in scope @n@ to elements of type @a@.
newtype NameMap (n :: S) a = NameMap { getNameMap :: IntMap a }
newtype NameMap (n :: S) a = NameMap { getNameMap :: IntMap a } deriving (Functor, Foldable, Traversable)

-- | An empty map belongs in the empty scope.
emptyNameMap :: NameMap VoidS a
Expand All @@ -818,6 +819,10 @@ emptyNameMap = NameMap IntMap.empty
nameMapToSubstitution :: NameMap i (e o) -> Substitution e i o
nameMapToSubstitution (NameMap m) = (UnsafeSubstitution m)

-- | Convert a 'NameMap' of expressions into a 'Scope'.
nameMapToScope :: NameMap n a -> Scope n
nameMapToScope (NameMap m) = UnsafeScope (IntMap.keysSet m)

-- | Extend a map with multiple mappings (by repeatedly applying 'addNameBinder').
--
-- Note that the input list is expected to have __at least__ the same number of elements
Expand Down
22 changes: 22 additions & 0 deletions haskell/free-foil/src/Control/Monad/Free/Foil.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ import Data.ZipMatchK
import Data.Coerce (coerce)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (mapMaybe)
import Data.Monoid (All (..))
import GHC.Generics (Generic)
import Unsafe.Coerce (unsafeCoerce)

-- | Scoped term under a (single) name binder.
data ScopedAST binder sig n where
Expand Down Expand Up @@ -376,3 +378,23 @@ convertFromScopedAST fromSig fromVar makePattern makeScoped f = \case
ScopedAST binder body ->
( makePattern binder
, makeScoped (convertFromAST fromSig fromVar makePattern makeScoped f body))

-- ** Unsinking AST

-- | Unsink an AST from a larger scope to a smaller scope.
unsinkAST :: (Foil.Distinct l, Foil.CoSinkable binder, Bifoldable sig) => Foil.Scope n -> AST binder sig l -> Maybe (AST binder sig n)
unsinkAST scope term
| all (`Foil.member` scope) (freeVarsOf term) = Just (unsafeCoerce term)
| otherwise = Nothing

-- | Get the free variables of an AST.
freeVarsOf :: (Foil.Distinct n, Foil.CoSinkable binder, Bifoldable sig) => AST binder sig n -> [Foil.Name n]
freeVarsOf = \case
Var name -> [name]
Node node -> bifoldMap freeVarsOfScopedAST freeVarsOf node

-- | Get the free variables of a scoped AST.
freeVarsOfScopedAST :: (Foil.Distinct n, Foil.CoSinkable binder, Bifoldable sig) => ScopedAST binder sig n -> [Foil.Name n]
freeVarsOfScopedAST (ScopedAST binder body) =
case Foil.assertDistinct binder of
Foil.Distinct -> mapMaybe (Foil.unsinkNamePattern binder) (freeVarsOf body)

0 comments on commit 65c6297

Please sign in to comment.