| 77 | | pr'pair txt left right = hsep |
| 78 | | [txt, pretty left, text "to", pretty right] |
| 79 | | pr'ops src tgt = pr'pair (text "op") src (getName tgt) |
| 80 | | pr'map fun = vcat . map (uncurry fun) . Map.toList |
| 81 | | smap = pr'map (pr'pair $ text "sort") $ sortMap mor |
| 82 | | omap = pr'map pr'ops $ opMap mor |
| 83 | | lmap = pr'map (pr'pair $ text "label") $ labelMap mor |
| | 91 | pr'pair txt left right = hsep |
| | 92 | [txt, pretty left, text "to", pretty right] |
| | 93 | pr'ops src tgt = pr'pair (text "op") src (getName tgt) |
| | 94 | pr'map fun = vcat . map (uncurry fun) . Map.toList |
| | 95 | smap = pr'map (pr'pair $ text "sort") $ sortMap mor |
| | 96 | omap = pr'map pr'ops $ opMap mor |
| | 97 | lmap = pr'map (pr'pair $ text "label") $ labelMap mor |
| 126 | | applyRenamings :: Morphism -> [Renaming] -> Morphism |
| 127 | | applyRenamings mor rens = let |
| 128 | | (ops, rest) = partitionRenamings rens |
| 129 | | add'ops = flip (foldr applyOpRenaming) ops |
| 130 | | add'rest = flip (foldr applyRenaming) rest |
| 131 | | in add'rest . add'ops $ mor |
| 132 | | |
| 133 | | -- | create a Morphism from an initial signature and a list of Renamings |
| 134 | | fromSignRenamings :: Sign -> [Renaming] -> Morphism |
| 135 | | fromSignRenamings = applyRenamings . identity |
| 136 | | |
| 137 | | |
| 138 | | -- TODO: Handle Attrs in Op Renamings. |
| 139 | | applyOpRenaming :: Renaming -> Morphism -> Morphism |
| 140 | | applyOpRenaming rename = let |
| 141 | | syms = renamingSymbols rename |
| 142 | | add'op = mapOpMap $ uncurry Map.insert syms |
| 143 | | use'op = mapTarget . uncurry Sign.renameOp syms |
| | 134 | -- | Separate Operator and other Renamings. |
| | 135 | partitionRenamings :: [Renaming] -> ([Renaming], [Renaming]) |
| | 136 | partitionRenamings = let |
| | 137 | is'op renaming = case renaming of |
| | 138 | OpRenaming1 _ _ -> True |
| | 139 | OpRenaming2 _ _ _ _ -> True |
| | 140 | _ -> False |
| | 141 | in partition is'op |
| | 142 | |
| | 143 | -- ** to apply Renamings to Morphisms |
| | 144 | |
| | 145 | -- | Insert an 'Operator' 'Renaming' into a 'Morphism'. |
| | 146 | -- Iff apply is True, apply the Renaming to the Morphism's target Signature. |
| | 147 | insertOpRenaming :: Bool -> Renaming -> Morphism -> Morphism |
| | 148 | insertOpRenaming apply rename = let |
| | 149 | syms = renamingSymbols rename |
| | 150 | add'op = mapOpMap $ uncurry Map.insert syms |
| | 151 | use'op attrs = if apply |
| | 152 | then mapTarget $ uncurry Sign.renameOp syms attrs |
| | 153 | else id |
| 149 | | applyRenaming :: Renaming -> Morphism -> Morphism |
| 150 | | applyRenaming rename = let |
| 151 | | syms = renamingSymbols rename |
| 152 | | add'sort = mapSortMap $ uncurry Map.insert syms |
| 153 | | use'sort = mapTarget $ uncurry Sign.renameSort syms |
| 154 | | ren'sort = mapOpMap $ uncurry renameSortOpMap syms |
| 155 | | add'labl = mapLabelMap $ uncurry Map.insert syms |
| 156 | | use'labl = mapTarget $ uncurry Sign.renameLabel syms |
| | 159 | -- | Insert a non-Operator 'Renaming' into a 'Morphism'. |
| | 160 | -- ^ iff True, apply the Renaming to the target Sign |
| | 161 | insertRenaming :: Bool -> Renaming -> Morphism -> Morphism |
| | 162 | insertRenaming apply rename = let |
| | 163 | syms = renamingSymbols rename |
| | 164 | add'sort = mapSortMap $ uncurry Map.insert syms |
| | 165 | use'sort = if apply |
| | 166 | then mapTarget $ uncurry Sign.renameSort syms |
| | 167 | else id |
| | 168 | ren'sort = mapOpMap $ uncurry renameSortOpMap syms |
| | 169 | add'labl = mapLabelMap $ uncurry Map.insert syms |
| | 170 | use'labl = if apply |
| | 171 | then mapTarget $ uncurry Sign.renameLabel syms |
| | 172 | else id |
| 162 | | |
| 163 | | -- | create a Morphism from the initial signatures and a list of Renamings |
| 164 | | fromSignsRenamings :: Sign -> Sign -> [Renaming] -> Morphism |
| 165 | | fromSignsRenamings sign1 sign2 rens = let |
| 166 | | (ops, rest) = partitionRenamings rens |
| 167 | | add'ops = flip (foldr insertOpRenaming) ops |
| 168 | | add'rest = flip (foldr insertRenaming) rest |
| 169 | | mor = inclusion sign1 sign2 |
| 170 | | in add'rest . add'ops $ mor |
| 171 | | |
| 172 | | -- TODO: Handle Attrs in Op Renamings. |
| 173 | | insertOpRenaming :: Renaming -> Morphism -> Morphism |
| 174 | | insertOpRenaming rename = let |
| 175 | | syms = renamingSymbols rename |
| 176 | | add'op = mapOpMap $ uncurry Map.insert syms |
| 177 | | in case rename of |
| 178 | | OpRenaming1 _ _ -> add'op |
| 179 | | OpRenaming2 _ _ _ _ -> add'op |
| 180 | | _ -> id |
| 181 | | |
| 182 | | insertRenaming :: Renaming -> Morphism -> Morphism |
| 183 | | insertRenaming rename = let |
| 184 | | syms = renamingSymbols rename |
| 185 | | add'sort = mapSortMap $ uncurry Map.insert syms |
| 186 | | ren'sort = mapOpMap $ uncurry renameSortOpMap syms |
| 187 | | add'labl = mapLabelMap $ uncurry Map.insert syms |
| 188 | | in case rename of |
| 189 | | SortRenaming _ _ -> ren'sort . add'sort |
| 190 | | LabelRenaming _ _ -> add'labl |
| 191 | | _ -> id |
| 192 | | |
| 197 | | -- | extract the SymbolMap of a Morphism |
| 198 | | symbolMap :: Morphism -> SymbolMap |
| 199 | | symbolMap mor = Map.unions [sortMap mor, opMap mor, labelMap mor] |
| 200 | | |
| 201 | | -- | the empty Morphism |
| | 182 | -- | Insert 'Renaming's into a 'Morphism'. |
| | 183 | insertRenamings :: Bool -> Morphism -> [Renaming] -> Morphism |
| | 184 | insertRenamings apply mor rens = let |
| | 185 | (ops, rest) = partitionRenamings rens |
| | 186 | add'ops = flip (foldr $ insertOpRenaming apply) ops |
| | 187 | add'rest = flip (foldr $ insertRenaming apply) rest |
| | 188 | in add'rest . add'ops $ mor |
| | 189 | |
| | 190 | -- * Construction |
| | 191 | |
| | 192 | -- | Create a 'Morphism' from an initial 'Sign'ature and a list of 'Renaming's. |
| | 193 | fromSignRenamings :: Sign -> [Renaming] -> Morphism |
| | 194 | fromSignRenamings = insertRenamings True . identity |
| | 195 | |
| | 196 | -- | Create a 'Morphism' from a pair of 'Sign'atures and a list of 'Renaming's. |
| | 197 | fromSignsRenamings :: Sign -> Sign -> [Renaming] -> Morphism |
| | 198 | fromSignsRenamings sign1 sign2 = insertRenamings False $ inclusion sign1 sign2 |
| | 199 | |
| | 200 | -- | the empty 'Morphism' |
| 232 | | |
| 233 | | -- | the composition of two Morphisms |
| 234 | | compose :: Morphism -> Morphism -> Result Morphism |
| 235 | | compose f g |
| 236 | | | target f /= source g = fail |
| 237 | | "target of the first and source of the second morphism are different" |
| 238 | | | otherwise = let |
| 239 | | -- Take SymbolMap |mp| of each Morphism. |
| 240 | | -- Convert each SymbolMap to a function. |
| 241 | | -- Compose those functions. |
| 242 | | map'map :: (Morphism -> SymbolMap) -> Symbol -> Symbol |
| 243 | | map'map mp = mapAsFunction (mp g) . mapAsFunction (mp f) |
| 244 | | -- Map |x| via the composed SymbolMaps |mp| of both Morphisms. |
| 245 | | -- Insert the renaming mapping into a SymbolMap. |
| 246 | | insert :: (Morphism -> SymbolMap) -> Symbol -> SymbolMap -> SymbolMap |
| 247 | | insert mp x = let y = map'map mp x |
| 248 | | in if x == y then id else Map.insert x y |
| 249 | | -- Map each symbol in |items| via the combined SymbolMaps |mp|. |
| 250 | | compose'map :: (Morphism -> SymbolMap) -> (Sign -> SymbolSet) -> SymbolMap |
| 251 | | compose'map mp items = if Map.null (mp g) |
| 252 | | -- if the SymbolMap of |g| is empty, we use the one from |f| |
| 253 | | then mp f |
| 254 | | -- otherwise we start with the SymbolSet from |source f| |
| 255 | | -- and construct a combined SymbolMap by applying both |
| 256 | | -- SymbolMaps (from |f| and |g|) to each item in |insert| |
| 257 | | else Set.fold (insert mp) Map.empty $ items (source f) |
| 258 | | -- We want a morphism from |source f| to |target g|. |
| 259 | | mor = inclusion (source f) (target g) |
| 260 | | in return mor { |
| 261 | | sortMap = compose'map sortMap getSorts, |
| 262 | | opMap = compose'map opMap getOps, |
| 263 | | labelMap = compose'map labelMap getLabels |
| 264 | | } |
| 265 | | |
| 266 | | -- | check that a Morphism is legal |
| 267 | | isLegal :: Morphism -> Bool |
| 268 | | isLegal mor = let |
| 269 | | src = source mor |
| 270 | | tgt = target mor |
| 271 | | smap = sortMap mor |
| 272 | | omap = opMap mor |
| 273 | | lmap = labelMap mor |
| 274 | | subset mp items = let mapped = Set.map $ mapAsFunction mp |
| 275 | | in Set.isSubsetOf (mapped $ items src) $ items tgt |
| 276 | | lg'source = Sign.isLegal src |
| 277 | | lg'sortMap = subset smap getSorts |
| 278 | | lg'opMap = subset omap getOps |
| 279 | | lg'labelMap = subset lmap getLabels |
| 280 | | lg'target = Sign.isLegal tgt |
| 281 | | in all id [lg'source, lg'sortMap, lg'opMap, lg'labelMap, lg'target] |
| 282 | | |
| 283 | | -- | check that a Morphism is the identity |
| 284 | | isIdentity :: Morphism -> Bool |
| 285 | | isIdentity mor = source mor == target mor |
| 286 | | |
| 287 | | -- | check that a Morphism is an Inclusion |
| 288 | | isInclusion :: Morphism -> Bool |
| 289 | | isInclusion mor = let |
| 290 | | null'sortMap = Map.null (sortMap mor) |
| 291 | | null'opMap = Map.null (opMap mor) |
| 292 | | null'labelMap = Map.null (labelMap mor) |
| 293 | | in all id [null'sortMap, null'opMap, null'labelMap] |
| 294 | | |
| 295 | | -- | translate a Sentence along a Morphism |
| 296 | | mapSentence :: Morphism -> Sentence -> Result Sentence |
| 297 | | mapSentence mor = let |
| 298 | | smap = mapSorts (sortMap mor) |
| 299 | | omap = mapOps (opMap mor) |
| 300 | | lmap = mapLabels (labelMap mor) |
| 301 | | in return . lmap . smap . omap |
| 302 | | |
| | 232 | -- | the union of two 'Morphism's |
| | 244 | -- Just a shorthand for types inside compose. |
| | 245 | type Extraction = Morphism -> SymbolMap |
| | 246 | |
| | 247 | -- | the composition of two 'Morphism's |
| | 248 | compose :: Morphism -> Morphism -> Result Morphism |
| | 249 | compose f g |
| | 250 | | target f /= source g = fail |
| | 251 | "target of the first and source of the second morphism are different" |
| | 252 | | otherwise = let |
| | 253 | -- Take SymbolMap |mp| of each Morphism. |
| | 254 | -- Convert each SymbolMap to a function. |
| | 255 | -- Compose those functions. |
| | 256 | map'map :: Extraction -> Symbol -> Symbol |
| | 257 | map'map mp = mapAsFunction (mp g) . mapAsFunction (mp f) |
| | 258 | -- Map |x| via the composed SymbolMaps |mp| of both Morphisms. |
| | 259 | -- Insert the renaming mapping into a SymbolMap. |
| | 260 | insert :: Extraction -> Symbol -> SymbolMap -> SymbolMap |
| | 261 | insert mp x = let y = map'map mp x |
| | 262 | in if x == y then id else Map.insert x y |
| | 263 | -- Map each symbol in |items| via the combined SymbolMaps |mp|. |
| | 264 | compose'map :: Extraction -> (Sign -> SymbolSet) -> SymbolMap |
| | 265 | compose'map mp items = if Map.null (mp g) |
| | 266 | -- if the SymbolMap of |g| is empty, we use the one from |f| |
| | 267 | then mp f |
| | 268 | -- otherwise we start with the SymbolSet from |source f| |
| | 269 | -- and construct a combined SymbolMap by applying both |
| | 270 | -- SymbolMaps (from |f| and |g|) to each item in |insert| |
| | 271 | else Set.fold (insert mp) Map.empty $ items (source f) |
| | 272 | -- We want a morphism from |source f| to |target g|. |
| | 273 | mor = inclusion (source f) (target g) |
| | 274 | in return mor { |
| | 275 | sortMap = compose'map sortMap getSorts, |
| | 276 | opMap = compose'map opMap getOps, |
| | 277 | labelMap = compose'map labelMap getLabels |
| | 278 | } |
| | 279 | |
| | 280 | -- * Testing |
| | 281 | |
| | 282 | -- | True iff the 'Morphism' is the identity |
| | 283 | isIdentity :: Morphism -> Bool |
| | 284 | isIdentity mor = source mor == target mor |
| | 285 | |
| | 286 | -- | True iff the 'Morphism' is an inclusion |
| | 287 | isInclusion :: Morphism -> Bool |
| | 288 | isInclusion mor = let |
| | 289 | null'sortMap = Map.null (sortMap mor) |
| | 290 | null'opMap = Map.null (opMap mor) |
| | 291 | null'labelMap = Map.null (labelMap mor) |
| | 292 | in all id [null'sortMap, null'opMap, null'labelMap] |
| | 293 | |
| | 294 | -- | True iff the 'Morphism' is legal |
| | 295 | isLegal :: Morphism -> Bool |
| | 296 | isLegal mor = let |
| | 297 | src = source mor |
| | 298 | tgt = target mor |
| | 299 | smap = sortMap mor |
| | 300 | omap = opMap mor |
| | 301 | lmap = labelMap mor |
| | 302 | subset mp items = let mapped = Set.map $ mapAsFunction mp |
| | 303 | in Set.isSubsetOf (mapped $ items src) $ items tgt |
| | 304 | lg'source = Sign.isLegal src |
| | 305 | lg'sortMap = subset smap getSorts |
| | 306 | lg'opMap = subset omap getOps |
| | 307 | lg'labelMap = subset lmap getLabels |
| | 308 | lg'target = Sign.isLegal tgt |
| | 309 | in all id [lg'source, lg'sortMap, lg'opMap, lg'labelMap, lg'target] |
| | 310 | |
| | 311 | -- * Conversion |
| | 312 | |
| | 313 | -- | extract the complete 'SymbolMap' of a 'Morphism' |
| | 314 | symbolMap :: Morphism -> SymbolMap |
| | 315 | symbolMap mor = Map.unions [sortMap mor, opMap mor, labelMap mor] |
| | 316 | |
| | 317 | -- * Modification |
| | 318 | |
| | 319 | -- | set a new target for a 'Morphism' |
| 336 | | getNewSorts :: [Symbol] -> Morphism -> [Symbol] |
| 337 | | getNewSorts ss morph = mapSorts (sortMap morph) ss |
| | 345 | -- * Application |
| | 346 | |
| | 347 | -- | translate a 'Sentence' along a 'Morphism' |
| | 348 | translateSentence :: Morphism -> Sentence -> Result Sentence |
| | 349 | translateSentence mor = let |
| | 350 | smap = mapSorts (sortMap mor) |
| | 351 | omap = mapOps (opMap mor) |
| | 352 | lmap = mapLabels (labelMap mor) |
| | 353 | in return . lmap . smap . omap |
| | 354 | |
| | 355 | -- | translate 'Sort's along a 'Morphism' |
| | 356 | translateSorts :: (HasSorts a) => Morphism -> a -> a |
| | 357 | translateSorts = mapSorts . sortMap |