translateDomainExpressionCrossScope scope _ nsid (L1.L1DomainExpressionLambda ss dh dexpr) = do
  let processDomainHeadMember (scope, sd, su) (L1.L1DHMScopedDomain name kind) = do
        sdid <- setScopedDomainName (L1.l1ScopedIdBS name) . L2.l2NextScopedDomainID <$> getL2Model
        modifyL2Model $ \mod -> mod {
          L2.l2NextScopedDomainID = (\(L2.L2ScopedDomainID _ v) -> L2.L2ScopedDomainID "!unknown" (v + 1)) sdid
        }
        return (scope { siDomainIDMap = M.insert name sdid (siDomainIDMap scope) }, (sdid, kind) : sd, su)
      processDomainHeadMember (scope, sd, su) (L1.L1DHMScopedUnit name) = do
        suid <- setScopedUnitName (L1.l1ScopedIdBS name) . L2.l2NextScopedUnitID <$> getL2Model
        modifyL2Model $ \mod -> mod {
            L2.l2NextScopedUnitID = (\(L2.L2ScopedUnitID _ v) -> L2.L2ScopedUnitID "!unknown" (v + 1)) suid
         }
        return (scope { siUnitIDMap = M.insert name suid (siUnitIDMap scope) }, sd, suid : su)
      processDomainHeadMember x _ = return x
  (scope', scopedDomains, scopedUnits) <-
        foldM processDomainHeadMember (scope, [], []) dh
  let processDomainHeadMember' (uc, de, dr) (L1.L1DHMUnitConstraint uex1 uex2) = do
        uex1' <- translateUnitExpression scope' ss nsid uex1
        uex2' <- translateUnitExpression scope' ss nsid uex2
        return ((uex1', uex2'):uc, de, dr)
      processDomainHeadMember' (uc, de, dr) (L1.L1DHMEquality dex1 dex2) = do
        dex1' <- translateDomainExpression scope' ss nsid dex1
        dex2' <- translateDomainExpression scope' ss nsid dex2
        return (uc, (dex1', dex2'):de, dr)
      processDomainHeadMember' (uc, de, dr) (L1.L1DHMRelation classex args) = do
        l2ClassEx <- translateClassExpression scope' ss nsid classex
        args' <- mapM (translateDomainExpression scope' ss nsid) args
        return (uc, de, (l2ClassEx, args'):dr)
      processDomainHeadMember' x _ = return x
  (uConstrs, dEqs, dRels) <-
    foldM processDomainHeadMember' ([], [], []) dh
  dexpr2 <- translateDomainExpression scope' ss nsid dexpr
  return $ (L2.L2DomainExpressionLambda ss scopedDomains scopedUnits uConstrs dEqs dRels dexpr2, scope')

-- | Translates an L1ClassExpression into an L2ClassExpression
translateDomainExpressionCrossScope scope _ nsid (L1.L1DomainExpressionLambda ss dh dexpr) = do
  let processDomainHeadMember (scope, sd, su) (L1.L1DHMScopedDomain name kind) = do
        sdid <- setScopedDomainName (L1.l1ScopedIdBS name) . L2.l2NextScopedDomainID <$> getL2Model
        modifyL2Model $ \mod -> mod {
          L2.l2NextScopedDomainID = (\(L2.L2ScopedDomainID _ v) -> L2.L2ScopedDomainID "!unknown" (v + 1)) sdid
        }
        return (scope { siDomainIDMap = M.insert name sdid (siDomainIDMap scope) }, (sdid, kind) : sd, su)
      processDomainHeadMember (scope, sd, su) (L1.L1DHMScopedUnit name) = do
        suid <- setScopedUnitName (L1.l1ScopedIdBS name) . L2.l2NextScopedUnitID <$> getL2Model
        modifyL2Model $ \mod -> mod {
            L2.l2NextScopedUnitID = (\(L2.L2ScopedUnitID _ v) -> L2.L2ScopedUnitID "!unknown" (v + 1)) suid
         }
        return (scope { siUnitIDMap = M.insert name suid (siUnitIDMap scope) }, sd, suid : su)
      processDomainHeadMember x _ = return x
  (scope', scopedDomains, scopedUnits) <-
        foldM processDomainHeadMember (scope, [], []) dh
  let processDomainHeadMember' (uc, de, dr) (L1.L1DHMUnitConstraint uex1 uex2) = do
        uex1' <- translateUnitExpression scope' ss nsid uex1
        uex2' <- translateUnitExpression scope' ss nsid uex2
        return ((uex1', uex2'):uc, de, dr)
      processDomainHeadMember' (uc, de, dr) (L1.L1DHMEquality dex1 dex2) = do
        dex1' <- translateDomainExpression scope' ss nsid dex1
        dex2' <- translateDomainExpression scope' ss nsid dex2
        return (uc, (dex1', dex2'):de, dr)
      processDomainHeadMember' (uc, de, dr) (L1.L1DHMRelation classex args) = do
        l2ClassEx <- translateClassExpression scope' ss nsid classex
        args' <- mapM (translateDomainExpression scope' ss nsid) args
        return (uc, de, (l2ClassEx, args'):dr)
      processDomainHeadMember' x _ = return x
  (uConstrs, dEqs, dRels) <-
    foldM processDomainHeadMember' ([], [], []) dh
  dexpr2 <- translateDomainExpression scope' ss nsid dexpr
  return $ (L2.L2DomainExpressionLambda ss scopedDomains scopedUnits uConstrs dEqs dRels dexpr2, scope')

-- | Translates an L1ClassExpression into an L2ClassExpression
translateDomainExpressionCrossScope scope _ nsid (L1.L1DomainExpressionLambda ss dh dexpr) = do
  let processDomainHeadMember (scope, sd, su) (L1.L1DHMScopedDomain name kind) = do
        sdid <- setScopedDomainName (L1.l1ScopedIdBS name) . L2.l2NextScopedDomainID <$> getL2Model
        modifyL2Model $ \mod -> mod {
          L2.l2NextScopedDomainID = (\(L2.L2ScopedDomainID _ v) -> L2.L2ScopedDomainID "!unknown" (v + 1)) sdid
        }
        return (scope { siDomainIDMap = M.insert name sdid (siDomainIDMap scope) }, (sdid, kind) : sd, su)
      processDomainHeadMember (scope, sd, su) (L1.L1DHMScopedUnit name) = do
        suid <- setScopedUnitName (L1.l1ScopedIdBS name) . L2.l2NextScopedUnitID <$> getL2Model
        modifyL2Model $ \mod -> mod {
            L2.l2NextScopedUnitID = (\(L2.L2ScopedUnitID _ v) -> L2.L2ScopedUnitID "!unknown" (v + 1)) suid
         }
        return (scope { siUnitIDMap = M.insert name suid (siUnitIDMap scope) }, sd, suid : su)
      processDomainHeadMember x _ = return x
  (scope', scopedDomains, scopedUnits) <-
        foldM processDomainHeadMember (scope, [], []) dh
  let processDomainHeadMember' (uc, de, dr) (L1.L1DHMUnitConstraint uex1 uex2) = do
        uex1' <- translateUnitExpression scope' ss nsid uex1
        uex2' <- translateUnitExpression scope' ss nsid uex2
        return ((uex1', uex2'):uc, de, dr)
      processDomainHeadMember' (uc, de, dr) (L1.L1DHMEquality dex1 dex2) = do
        dex1' <- translateDomainExpression scope' ss nsid dex1
        dex2' <- translateDomainExpression scope' ss nsid dex2
        return (uc, (dex1', dex2'):de, dr)
      processDomainHeadMember' (uc, de, dr) (L1.L1DHMRelation classex args) = do
        l2ClassEx <- translateClassExpression scope' ss nsid classex
        args' <- mapM (translateDomainExpression scope' ss nsid) args
        return (uc, de, (l2ClassEx, args'):dr)
      processDomainHeadMember' x _ = return x
  (uConstrs, dEqs, dRels) <-
    foldM processDomainHeadMember' ([], [], []) dh
  dexpr2 <- translateDomainExpression scope' ss nsid dexpr
  return $ (L2.L2DomainExpressionLambda ss scopedDomains scopedUnits uConstrs dEqs dRels dexpr2, scope')

-- | Translates an L1ClassExpression into an L2ClassExpression