swarm-0.1.0.0: src/Swarm/Language/Elaborate.hs
-- |
-- Module : Swarm.Language.Elaborate
-- Copyright : Brent Yorgey
-- Maintainer : byorgey@gmail.com
--
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Term elaboration which happens after type checking.
module Swarm.Language.Elaborate where
import Control.Lens (transform, (%~))
import Swarm.Language.Syntax
-- | Perform some elaboration / rewriting on a fully type-annotated
-- term, given its top-level type. This currently performs such
-- operations as rewriting @if@ expressions and recursive let
-- expressions to use laziness appropriately. In theory it could
-- also perform rewriting for overloaded constants depending on the
-- actual type they are used at, but currently that sort of thing
-- tends to make type inference fall over.
elaborate :: Term -> Term
elaborate =
-- Wrap all *free* variables in 'Force'. Free variables must be
-- referring to a previous definition, which are all wrapped in
-- 'TDelay'.
(fvT %~ TApp (TConst Force))
-- Now do additional rewriting on all subterms.
. transform rewrite
where
-- For recursive let bindings, rewrite any occurrences of x to
-- (force x). When interpreting t1, we will put a binding (x |->
-- delay t1) in the context.
rewrite (TLet True x ty t1 t2) = TLet True x ty (wrapForce x t1) (wrapForce x t2)
-- Rewrite any recursive occurrences of x inside t1 to (force x).
-- When a TDef is encountered at runtime its body will immediately
-- be wrapped in a VDelay. However, to make this work we also need
-- to wrap all free variables in any term with 'force' --- since
-- any such variables must in fact refer to things previously
-- bound by 'def'.
rewrite (TDef True x ty t1) = TDef True x ty (mapFree1 x (TApp (TConst Force)) t1)
-- Rewrite @f $ x@ to @f x@.
rewrite (TApp (TApp (TConst AppF) r) l) = TApp r l
-- Leave any other subterms alone.
rewrite t = t
wrapForce :: Var -> Term -> Term
wrapForce x = mapFree1 x (TApp (TConst Force))