content: {- |
  Module      :  ./Maude/Meta/AsSymbol.hs
  Description :  Viewing Maude data types as Symbols
  Copyright   :  (c) Martin Kuehl, Uni Bremen 2008-2009
  License     :  GPLv2 or higher, see LICENSE.txt
  
  Maintainer  :  mkhl@informatik.uni-bremen.de
  Stability   :  experimental
  Portability :  portable
  
  Viewing Maude data types as Symbols.
  
  Defines a type class 'AsSymbol' that lets us treat Maude data types as
  'Symbol's, converting back and forth between them as needed.
  
  Consider importing "Maude.Meta" instead of this module.
  -}
  
  module Maude.Meta.AsSymbol (
      -- * The AsSymbol type class
      AsSymbol (..),
      -- * Auxiliary functions
      asSymbolSet,
      mapAsSymbol,
  ) where
  
  import Maude.AS_Maude
  import Maude.Symbol
  import Maude.Meta.HasName
  import Maude.Util
  
  import Data.Maybe (fromJust)
  import qualified Data.Set as Set
  
  -- * The AsSymbol type class
  
  {- | Represents something that can be converted into a 'Symbol'.
  Instances should only override /one/ of its class methods: -}
  --
  {- * Use 'asSymbol' when every member of the instance type can be
  represented as a 'Symbol'. -}
  --
  -- * Use 'asSymbolMaybe' otherwise.
  --
  -- Each function is defined in terms of the other one by default.
  
  class AsSymbol a where
      -- | Convert the input into a 'Symbol'.
      asSymbol :: a -> Symbol
      asSymbol = fromJust . asSymbolMaybe
      -- | Convert the input into 'Maybe' a 'Symbol'
      asSymbolMaybe :: a -> Maybe Symbol
      asSymbolMaybe = Just . asSymbol
  
  -- * Auxiliary functions
  
  -- | Instead of a single 'Symbol', convert the input into a 'SymbolSet'.
  asSymbolSet :: (AsSymbol a) => a -> SymbolSet
  asSymbolSet = maybe Set.empty Set.singleton . asSymbolMaybe
  
  {- | Apply a 'SymbolMap' to the input, then convert the result back to
  the original type. -}
  mapAsSymbol :: (AsSymbol a) => (Symbol -> a) -> SymbolMap -> a -> a
  mapAsSymbol ctr mp item = let extract = ctr . mapAsFunction mp
      in maybe item extract $ asSymbolMaybe item
  
  -- * Predefined 'AsSymbol' instances
  
  instance AsSymbol Symbol where
      asSymbol = id
  
  instance AsSymbol Type where
      asSymbol typ = case typ of
          TypeSort sort -> asSymbol sort
          TypeKind kind -> asSymbol kind
  
  instance AsSymbol Sort where
      asSymbol = Sort . getName
  
  instance AsSymbol Kind where
      asSymbol = Kind . getName
  
  instance AsSymbol LabelId where
      asSymbol = Labl . getName
  
  instance AsSymbol OpId where
      asSymbol = OpWildcard . getName
  
  instance AsSymbol StmntAttr where
      asSymbolMaybe attr = case attr of
          Label name -> Just $ Labl name
          _ -> Nothing
  
  instance AsSymbol Operator where
      asSymbol (Op op dom cod _) = let
              op' = getName op
              dom' = map asSymbol dom
              cod' = asSymbol cod
          in Operator op' dom' cod'
  
  instance AsSymbol Term where
      asSymbolMaybe term = case term of
          Const _ _ -> Nothing
          Var _ _ -> Nothing
          Apply op ts tp -> let
                  dom = map (asSymbol . getTermType) ts
                  cod = asSymbol tp
              in Just $ Operator op dom cod
  