1
1
mirror of https://github.com/github/semantic.git synced 2024-11-28 10:15:55 +03:00

Provide a bunch more Scope machinery.

This commit is contained in:
Rob Rix 2019-07-15 10:50:42 -04:00
parent cf40f50459
commit 6a237b7f41
No known key found for this signature in database
GPG Key ID: F188A01508EA1CF7

View File

@ -4,12 +4,18 @@ module Data.Scope
, incr
, Scope(..)
, foldScope
, fromScope
, toScope
, bind1
, bind
, bindEither
, instantiate1
, instantiate
, instantiateEither
) where
import Control.Applicative (liftA2)
import Control.Monad ((>=>))
import Control.Monad ((>=>), guard)
import Control.Monad.Trans.Class
import Data.Function (on)
@ -27,12 +33,11 @@ instance Monad (Incr a) where
Z a >>= _ = Z a
S a >>= f = f a
match :: Applicative f => (b -> Maybe a) -> b -> Incr a (f b)
match f x | Just y <- f x = Z y
| otherwise = S (pure x)
match :: Applicative f => (b -> Either a c) -> b -> Incr a (f c)
match f x = either Z (S . pure) (f x)
fromIncr :: (a -> b) -> Incr a b -> b
fromIncr f = incr f id
matchMaybe :: (b -> Maybe a) -> (b -> Either a b)
matchMaybe f a = maybe (Right a) Left (f a)
incr :: (a -> c) -> (b -> c) -> Incr a b -> c
incr z s = \case { Z a -> z a ; S b -> s b }
@ -67,10 +72,31 @@ foldScope :: (forall a . Incr z (n a) -> m (Incr z (n a)))
-> Scope z n b
foldScope k go h = Scope . go (k . fmap (go h)) . unScope
fromScope :: Monad f => Scope a f b -> f (Incr a b)
fromScope = unScope >=> sequenceA
toScope :: Applicative f => f (Incr a b) -> Scope a f b
toScope = Scope . fmap (fmap pure)
-- | Bind occurrences of a variable in a term, producing a term in which the variable is bound.
bind1 :: (Applicative f, Eq a) => a -> f a -> Scope () f a
bind1 n = bind (guard . (== n))
bind :: Applicative f => (b -> Maybe a) -> f b -> Scope a f b
bind name = Scope . fmap (match name) -- FIXME: succ as little of the expression as possible, cf https://twitter.com/ollfredo/status/1145776391826358273 — can this even be done generically?
bind f = bindEither (matchMaybe f)
bindEither :: Applicative f => (b -> Either a c) -> f b -> Scope a f c
bindEither f = Scope . fmap (match f) -- FIXME: succ as little of the expression as possible, cf https://twitter.com/ollfredo/status/1145776391826358273
-- | Substitute a term for the free variable in a given term, producing a closed term.
instantiate1 :: Monad f => f b -> Scope a f b -> f b
instantiate1 t = instantiate (const t)
instantiate :: Monad f => (a -> f b) -> Scope a f b -> f b
instantiate f = unScope >=> fromIncr f
instantiate f = instantiateEither (either f pure)
instantiateEither :: Monad f => (Either a b -> f c) -> Scope a f b -> f c
instantiateEither f = unScope >=> incr (f . Left) (>>= f . Right)