File: SimpleReflect.hs

package info (click to toggle)
haskell-show 0.4.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 92 kB
  • sloc: haskell: 199; makefile: 2
file content (253 lines) | stat: -rw-r--r-- 9,747 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  SimpleReflect
-- Copyright   :  (c) 2008 Twan van Laarhoven
-- License     :  BSD-style
--
-- Maintainer  :  twanvl@gmail.com
-- Stability   :  experimental
-- Portability :  portable
--
-- Simple reflection of Haskell expressions containing variables.
--
-----------------------------------------------------------------------------
module SimpleReflect
    ( Expr
    , var, fun, expr, reduce
    , a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
    ) where

import Control.Applicative

{- -- Lennart Augustsson's extensions, temporarily disabled.
import Control.Monad.State hiding(lift)
-}

import Data.Maybe (fromMaybe)
import Data.Ord (comparing)
import Data.Generics (Typeable, Data)


------------------------------------------------------------------------------
-- Data type
------------------------------------------------------------------------------

data Expr = Expr
   { showExpr   :: Int -> ShowS
   , intExpr    :: Maybe Integer
   , doubleExpr :: Maybe Double
   , reduced    :: Maybe Expr
   } deriving (Typeable, Data)

instance Show Expr where
    showsPrec pp rr = showExpr rr pp

-- Default expression
emptyExpr :: Expr
emptyExpr = Expr { showExpr   = \_ -> showString ""
                 , intExpr    = Nothing
                 , doubleExpr = Nothing
                 , reduced    = Nothing
                 }

------------------------------------------------------------------------------
-- Lifting and combining expressions
------------------------------------------------------------------------------

-- | A variable
var :: String -> Expr
var ss = emptyExpr { showExpr = \_ -> showString ss }

lift :: Show a => a -> Expr
lift xx = emptyExpr { showExpr = (`showsPrec` xx) }

data Fixity = L | R deriving Eq

-- | A operator as expression
op :: Fixity -> Int -> String -> Expr -> Expr -> Expr
op fix prec opp aa bb = emptyExpr { showExpr = showFun }
 where showFun pp = showParen (pp > prec)
                     $ showExpr aa (if fix == L then prec else prec + 1)
                     . showString opp
                     . showExpr bb (if fix == R then prec else prec + 1)

------------------------------------------------------------------------------
-- Adding numeric results
------------------------------------------------------------------------------
iOp :: (Expr -> Expr) -> (Integer -> Integer) -> Expr -> Expr
iOp  rr ff aa   = (rr a  ) { intExpr    = ff <$> intExpr    aa }
iOp2 :: (Expr -> Expr -> Expr) -> (Integer -> Integer -> Integer) -> Expr -> Expr -> Expr
iOp2 rr ff aa bb = (rr aa bb) { intExpr    = ff <$> intExpr    aa <*> intExpr    bb }
dOp :: (Expr -> Expr) -> (Double -> Double) -> Expr -> Expr
dOp  rr ff aa   = (rr aa  ) { doubleExpr = ff <$> doubleExpr aa }
dOp2 :: (Expr -> Expr -> Expr) -> (Double -> Double -> Double) -> Expr -> Expr -> Expr
dOp2 rr ff aa bb = (rr aa bb) { doubleExpr = ff <$> doubleExpr aa <*> doubleExpr bb }

withReduce :: (Expr -> Expr) -> Expr -> Expr
withReduce rr aa    = let rrr = rr aa in
                    rrr { reduced = withReduce rr <$> reduced aa
                               <|> fromInteger <$> intExpr    rrr
                               <|> fromDouble  <$> doubleExpr rrr
                       }
withReduce2 :: (Expr -> Expr -> Expr) -> Expr -> Expr -> Expr
withReduce2 rr aa bb = let rrr = rr aa bb in
                    rrr { reduced = (\aa' -> withReduce2 rr aa' b) <$> reduced aa
                               <|> withReduce2 rr aa <$> reduced bb
                               <|> fromInteger <$> intExpr    rrr
                               <|> fromDouble  <$> doubleExpr rrr
                       }

------------------------------------------------------------------------------
-- Function types
------------------------------------------------------------------------------

class FromExpr a where
    fromExpr :: Expr -> a

instance FromExpr Expr where
    fromExpr = id

instance (Show a, FromExpr b) => FromExpr (a -> b) where
    fromExpr ff aa = fromExpr $ op L 10 " " ff (lift aa)

fun :: FromExpr a => String -> a
fun = fromExpr . var

------------------------------------------------------------------------------
-- Variables!
------------------------------------------------------------------------------

a,b,c,d,e,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z :: Expr
[a,b,c,d,e,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
   = [var [xx] | xx <- ['a'..'e']++['i'..'z']]

f,g,h :: FromExpr a => a
f = fun "f"
g = fun "g"
h = fun "h"

------------------------------------------------------------------------------
-- Forcing conversion & evaluation
------------------------------------------------------------------------------

-- | Force something to be an expression
expr :: Expr -> Expr
expr = id

-- | Reduce (evaluate) an expression once
--   for example 1 + 2 + 3 + 4 ==> 3 + 3 + 4
reduce :: Expr -> Expr
reduce ee = fromMaybe ee (reduced ee)

------------------------------------------------------------------------------
-- Numeric classes
------------------------------------------------------------------------------

instance Eq Expr where
    Expr{ intExpr    = Just aa } == Expr{ intExpr    = Just bb }  =  aa == bb
    Expr{ doubleExpr = Just aa } == Expr{ doubleExpr = Just bb }  =  aa == bb
    aa                           == bb                            =  show aa == show bb

instance Ord Expr where
    compare Expr{ intExpr    = Just aa } Expr{ intExpr    = Just bb }  =  compare aa bb
    compare Expr{ doubleExpr = Just aa } Expr{ doubleExpr = Just bb }  =  compare aa bb
    compare aa                           bb                            =  comparing show aa bb
    min = fun "min" `iOp2` min `dOp2` min
    max = fun "max" `iOp2` max `dOp2` max

instance Num Expr where
    (+)    = withReduce2 $ op L 6 " + " `iOp2` (+)   `dOp2` (+)
    (-)    = withReduce2 $ op L 6 " - " `iOp2` (-)   `dOp2` (-)
    (*)    = withReduce2 $ op L 7 " * " `iOp2` (*)   `dOp2` (*)
    negate = withReduce  $ fun "negate" `iOp` negate `dOp` negate
    abs    = withReduce  $ fun "abs"    `iOp` abs    `dOp` abs
    signum = withReduce  $ fun "signum" `iOp` signum `dOp` signum
    fromInteger ii = (lift ii)
                     { intExpr    = Just ii
                     , doubleExpr = Just $ fromInteger ii }

instance Real Expr where
    toRational xpr = case (doubleExpr xpr, intExpr xpr) of
          (Just dd,_) -> toRational dd
          (_,Just ii) -> toRational ii
          _          -> error "not a number"

instance Integral Expr where
    quotRem aa bb = (quot aa bb, rem aa bb)
    divMod  aa bb = (div aa bb, mod aa bb)
    quot = withReduce2 $ op L 7 " `quot` " `iOp2` quot
    rem  = withReduce2 $ op L 7 " `rem` "  `iOp2` rem
    div  = withReduce2 $ op L 7 " `div` "  `iOp2` div
    mod  = withReduce2 $ op L 7 " `mod` "  `iOp2` mod
    toInteger xpr = case intExpr xpr of
          Just ii -> ii
          _      -> error "not a number"

instance Fractional Expr where
    (/)   = withReduce2 $ op L 7 " / " `dOp2` (/)
    recip = withReduce  $ fun "recip"  `dOp` recip
    fromRational rr = fromDouble (fromRational rr)

fromDouble :: Double -> Expr
fromDouble dd = (lift dd) { doubleExpr = Just dd }

instance Floating Expr where
    pi    = (var "pi") { doubleExpr = Just pi }
    exp   = withReduce  $ fun "exp"   `dOp` exp
    sqrt  = withReduce  $ fun "sqrt"  `dOp` sqrt
    log   = withReduce  $ fun "log"   `dOp` log
    (**)  = withReduce2 $ op R 8 "**" `dOp2` (**)
    sin   = withReduce  $ fun "sin"   `dOp` sin
    cos   = withReduce  $ fun "cos"   `dOp` cos
    sinh  = withReduce  $ fun "sinh"  `dOp` sinh
    cosh  = withReduce  $ fun "cosh"  `dOp` cosh
    asin  = withReduce  $ fun "asin"  `dOp` asin
    acos  = withReduce  $ fun "acos"  `dOp` acos
    atan  = withReduce  $ fun "atan"  `dOp` atan
    asinh = withReduce  $ fun "asinh" `dOp` asinh
    acosh = withReduce  $ fun "acosh" `dOp` acosh
    atanh = withReduce  $ fun "atanh" `dOp` atanh

instance Enum Expr where
    succ   = withReduce  $ fun "succ" `iOp` succ `dOp` succ
    pred   = withReduce  $ fun "pred" `iOp` pred `dOp` pred
    toEnum = fun "toEnum"
    fromEnum = fromEnum . toInteger
    enumFrom       aa     = map fromInteger $ enumFrom       (toInteger aa)
    enumFromThen   aa bb  = map fromInteger $ enumFromThen (toInteger aa) (toInteger bb)
    enumFromTo     aa  cc = map fromInteger $ enumFromTo (toInteger aa) (toInteger cc)
    enumFromThenTo aa bb cc = map fromInteger $ enumFromThenTo (toInteger aa) (toInteger bb) (toInteger cc)

instance Bounded Expr where
    minBound = var "minBound"
    maxBound = var "maxBound"

{- -- Lennart Augustsson's Extensions, temporarily disabled.
See <http://augustss.blogspot.com/2008/03/in-recent-blog-post-by-twan-van.html>.

instance (Show a, ExprArg a, Show r) => Show (a -> r) where
    showsPrec _ f = showString "\\ " . showsPrec 0 v . showString " -> " .
                    showsPrec 0 (f v)
      where v = evalState exprArg vars
            dummy = evalState exprArg $ repeat "_"
            vars = supply \\ tokenize (show $ f dummy)
            supply = ["x","y","z"] ++ [ "x" ++ show i | i <- [1..]]
            tokenize "" = []
            tokenize s = case lex s of (x,s') : _ -> x : tokenize s'

class ExprArg a where
    exprArg :: State [String] a

instance ExprArg Expr where
    exprArg = do v:vs <- get; put vs; return (var v)

instance ExprArg () where
    exprArg = return ()

instance (ExprArg a, ExprArg b) => ExprArg (a, b) where
    exprArg = liftM2 (,) exprArg exprArg

instance (ExprArg a, ExprArg b, ExprArg c) => ExprArg (a, b, c) where
    exprArg = liftM3 (,,) exprArg exprArg exprArg
-}