ideas-1.0: src/Service/OpenMathSupport.hs
{-# LANGUAGE Rank2Types #-}
-----------------------------------------------------------------------------
-- Copyright 2011, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Service.OpenMathSupport
( -- * Conversion functions to/from OpenMath
toOpenMath, fromOpenMath
, toOMOBJ, fromOMOBJ
) where
import Common.Library
import Control.Monad
import Data.Char
import Data.List
import Text.OpenMath.Dictionary.Arith1
import Text.OpenMath.Dictionary.Fns1
import Text.OpenMath.Object
import qualified Text.OpenMath.Symbol as OM
-----------------------------------------------------------------------------
-- Utility functions for conversion to/from OpenMath
toOpenMath :: Monad m => Exercise a -> a -> m OMOBJ
toOpenMath ex a = do
v <- hasTermViewM ex
return (toOMOBJ (build v a))
fromOpenMath :: MonadPlus m => Exercise a -> OMOBJ -> m a
fromOpenMath ex omobj = do
v <- hasTermViewM ex
a <- fromOMOBJ omobj
matchM v a
toOMOBJ :: IsTerm a => a -> OMOBJ
toOMOBJ = rec . toTerm
where
rec term =
case term of
TVar s -> OMV s
TCon s -> OMS (idToSymbol (getId s))
TMeta i -> OMV ('$' : show i)
TNum n -> OMI n
TFloat d -> OMF d
TApp _ _ -> let (f, xs) = getSpine term
in make (map rec (f:xs))
make [OMS s, OMV x, body] | s == lambdaSymbol =
OMBIND (OMS s) [x] body
make [OMS s, a, b, c] | s == mfSymbol = -- special for mixed fraction symbol
OMA [OMS plusSymbol, a, OMA [OMS divideSymbol, b, c]]
make xs = OMA xs
fromOMOBJ :: (MonadPlus m, IsTerm a) => OMOBJ -> m a
fromOMOBJ = (>>= fromTerm) . rec
where
rec omobj =
case omobj of
OMV x -> case isMeta x of
Just n -> return (TMeta n)
Nothing -> return (TVar x)
OMS s -> return (symbol (newSymbol (OM.dictionary s # OM.symbolName s)))
OMI n -> return (TNum n)
OMF a -> return (TFloat a)
OMA (x:xs) -> liftM2 makeTerm (rec x) (mapM rec xs)
OMBIND binder xs body ->
rec (OMA (binder:map OMV xs++[body]))
_ -> fail "Invalid OpenMath object"
isMeta ('$':xs) = Just (foldl' (\a b -> a*10+ord b-48) 0 xs) -- '
isMeta _ = Nothing
idToSymbol :: Id -> OM.Symbol
idToSymbol a
| null (qualifiers a) =
OM.extraSymbol (unqualified a)
| otherwise =
OM.makeSymbol (qualification a) (unqualified a)
hasTermViewM :: Monad m => Exercise a -> m (View Term a)
hasTermViewM = maybe (fail "No support for terms") return . hasTermView
mfSymbol :: OM.Symbol
mfSymbol = OM.makeSymbol "extra" "mixedfraction"