- | Checks whether a sub-expression in a given environment can be lifted out
liftable :: PrjDict dom -> Env dom -> ASTF dom a -> Bool
liftable pd env a = independent pd env a && not (isVariable pd a) && heuristic
    -- Lifting dependent expressions is semantically incorrect
    -- Lifting variables would cause `codeMotion` to loop
  where
    heuristic = inLambda env || (counter env (ASTE a) > 1)

-- | Update the environment when going under a lambda that binds the given variable. This lambda is
-- assumed to be called multiple times, so that hoisting is worthwhile.

liftable :: PrjDict dom -> Env dom -> ASTF dom a -> Bool
liftable pd env a = independent pd env a && not (isVariable pd a) && heuristic
    -- Lifting dependent expressions is semantically incorrect
    -- Lifting variables would cause `codeMotion` to loop
  where
    heuristic = inLambda env || (counter env (ASTE a) > 1)

-- | Update the environment when going under a lambda that binds the given variable. This lambda is
-- assumed to be called multiple times, so that hoisting is worthwhile.
liftable pd env a = independent pd env a && not (isVariable pd a) && heuristic
    -- Lifting dependent expressions is semantically incorrect
    -- Lifting variables would cause `codeMotion` to loop
  where
    heuristic = inLambda env || (counter env (ASTE a) > 1)

-- | Update the environment when going under a lambda that binds the given variable. This lambda is
-- assumed to be called multiple times, so that hoisting is worthwhile.