hascal 1.1 → 1.3
raw patch · 3 files changed
+130/−47 lines, 3 filesnew-uploaderPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Hascal: data Complex a :: * -> *
+ Hascal: prettyPrint :: (Show t, RealFloat t) => Complex t -> String
- Hascal: eval :: [(Char, CReal -> CReal -> CReal)] -> String -> CReal
+ Hascal: eval :: (Read t, RealFloat t) => [(Char, Complex t -> Complex t -> Complex t)] -> String -> Maybe (Complex t)
- Hascal: hascal :: String -> CReal
+ Hascal: hascal :: (Read t, RealFloat t) => String -> Maybe (Complex t)
- Hascal: operators :: [(Char, CReal -> CReal -> CReal)]
+ Hascal: operators :: RealFloat t => [(Char, Complex t -> Complex t -> Complex t)]
Files
- Hascal.hs +99/−22
- Main.hs +6/−5
- hascal.cabal +25/−20
Hascal.hs view
@@ -1,67 +1,144 @@--- |'Hascal' is both a simple but extendable calculator library for Haskell+-- |Hascal is both a simple but extendable calculator library for Haskell -- and a command-line program using it. -- -- Also, its source code is a nice example for a minimalistic Haskell project.+-- +-- Some examples for the usage of the command-line program:+-- +-- >>> hascal 1+2+-- 3.0+-- +-- >>> hascal 1+2*3-4/198^2+-- 6.99989796959493929190898887868584838281807978777676+-- +-- Also, preceding exclamation marks mean that the following number is+-- imaginary, that is, you have to multiply it with i. E.g.:+-- +-- >>> hascal _1 ^ 0.5+-- !1.0+-- +-- And as you can see, negative numbers are preceded by a underscore.+-- +-- Although hascal itself doesn't understand brackets, you can use your shell+-- to get that functionality, like this (using bash):+-- +-- >>> hascal e ^ $(hascal i*pi)+-- -1.0+-- +-- Speaking of shells, you should consider that your shell might extend an+-- asterisk (*) to the files at the current directory, like here:+-- +-- >>> echo *+-- _darcs dist hascal.cabal Hascal.hs LICENSE Main.hs README.org Setup.hs+-- +-- That's why this might not work:+-- +-- >>> hascal 1 * 2+-- Error. :(+-- +-- But you could do this instead:+-- +-- >>> hascal 1*2+-- 2+-- +-- Yeah, that's it. Hascal is really minimalistic.+-- And I'm not planning to extend it much. module Hascal (+ -- * Types+ -- |Just re-exporting the 'Complex' data-type for simplicity and comfort.+ Complex, -- * Functions -- ** Operators operators, -- ** Evaluators eval,- hascal+ hascal,+ -- ** Pretty Printers+ prettyPrint ) where -import Control.Arrow (second)-import Data.Function (on)-import Data.Number.CReal +import Control.Arrow (second)+import Data.Complex (Complex(..))+import Data.Functor ((<$>))+import Data.List (find) ++ -- |'operators' is the default list of operators. -- -- An operator consists of one character and a function with of type--- @CReal -> CReal -> CReal@.+-- @Number -> Number -> Number@. -- -- 'operators' includes: -- --- * addition, represented by @\'+\'@+-- * addition, represented by @\'+\'@, -- --- * subtraction, represented by @\'-\'@+-- * subtraction, represented by @\'-\'@, -- --- * multiplication, represented by @\'c\'@+-- * multiplication, represented by @\'c\'@, -- --- * division, represented by @\'\/\'@+-- * division, represented by @\'\/\'@, -- --- * exponentiation, represented by @\'^\'@+-- * exponentiation, represented by @\'^\'@, and -- --- * logarithming (with flipped arguments, see below), represented by @\'?\'@+-- * logarithming (with flipped arguments, see below), represented by @\'?\'@, -- -- such that these laws are held: -- -- > (a - b == c) == (a == b + c) -- > (a / b == c) == (a == b * c) -- > (a ? b == c) == (a == b ^ c)-operators :: [(Char, CReal -> CReal -> CReal)]+operators :: RealFloat t+ => [(Char, Complex t -> Complex t -> Complex t)] operators = [ ('+', (+)) , ('-', (-)) , ('/', (/)) , ('*', (*)) , ('^', (**)) , ('?', flip logBase)- ]-- Respecting operator precedence,- -- you can add custom infix operators.+ ] + -- |'eval' gets a list of operators and a string containing a mathematical -- expression/term which only uses those operators listed in the first -- argument, and returns the result of that term.-eval :: [(Char, CReal -> CReal -> CReal)] -> String -> CReal-eval [] a = read a-eval l@((c,f):s) a | z /= "" = on f (eval l.($m)) fst snd- | otherwise = eval s a- where m@(_,z) = second (drop 1) $ break (==c) a+eval :: (Read t, RealFloat t)+ => [(Char, Complex t -> Complex t -> Complex t)] -- ^ list of operators+ -> String -- ^ string containing term+ -> Maybe (Complex t) -- ^ just result, or nothing+eval [] ('!':a) = ((0:+1)*) <$> findOrRead a+eval [] ('_':a) = negate <$> findOrRead a+eval [] a = findOrRead a+eval l@((c,f):s) a | z /= "" = case (eval l y,eval l z) of+ (Just n,Just m) -> Just (f n m)+ _ -> Nothing+ | otherwise = eval s a+ where (y,z) = second (drop 1) $ break (==c) a +findOrRead :: (Read t, Floating t) => String -> Maybe (Complex t)+findOrRead s = maybe (maybeRead s) (Just . fst) $+ find ((==s) . snd) [(pi:+0,"pi"),(exp 1:+0,"e"),(0:+1,"i")]+++maybeRead :: (Read t, Num t) => String -> Maybe (Complex t)+maybeRead s | any (null . snd) (reads s :: [(Double,String)])+ = Just (read s:+0)+ | otherwise+ = Nothing++ -- |'hascal' is the default evaluator: -- --- > hascal = eval operators-hascal :: String -> CReal+-- @ hascal = 'eval' 'operators' @+hascal :: (Read t, RealFloat t) => String -> Maybe (Complex t) hascal = eval operators+++-- |'prettyPrint' prints a number nicely.+-- E.g., it doesn't show the real or imaginary part of the number if it's @0@.+prettyPrint :: (Show t, RealFloat t) => Complex t -> String+prettyPrint (r:+0) = show r+prettyPrint (0:+i) = '!' : show i+prettyPrint (r:+i) = show r ++ " + !" ++ show i
Main.hs view
@@ -1,11 +1,12 @@ module Main where -import Control.Monad (liftM2, unless)-import Data.Number.CReal-import Hascal-import System.Environment (getArgs)+import Control.Monad+import Hascal+import System.Environment+import Data.Number.CReal main :: IO () main = getArgs >>= liftM2 unless null- (putStrLn . showCReal 80 . hascal . concat)+ (putStrLn . maybe "Error. :(" prettyPrint .+ (hascal :: String -> Maybe (Complex CReal)) . concat)
hascal.cabal view
@@ -1,26 +1,30 @@-name: hascal-version: 1.1-synopsis: a minimal, extensible and precise calculator-description: Hascal is a minimal calculator with infix-operations- supporting addition, subtraction, division, multiplication,- exponentiation and logarithming. Brackets are not supported- yet.- Futhermore, it's easy to add custom operators.-stability: provisional-category: Math, Console, Tools, Utility, Utils, Parsing-homepage: https://github.com/MekeorMelire/hascal-bug-reports: https://github.com/MekeorMelire/hascal/issues-license: GPL-license-file: LICENSE-copyright: © 2012 Mekeor Melire-author: Mekeor Melire-maintainer: Mekeor Melire <mekeor.melire@googlemail.com>-tested-with: GHC ==7.0.4-cabal-version: >= 1.6-build-type: Simple+name: hascal+version: 1.3+synopsis: A minimal, extensible and precise calculator+description: Hascal is a minimal calculator with infix-operations+ supporting addition, subtraction, division, multiplication,+ exponentiation and logarithming.+ Futhermore, it's easy to add custom operators.+stability: provisional+category: Math, Console, Tools, Utility, Utils, Parsing+homepage: http://darcsden.com/mekeor/hascal+bug-reports: https://github.com/MekeorMelire/hascal/issues+license: GPL+license-file: LICENSE+copyright: 2012 Mekeor Melire+author: Mekeor Melire <mekeor.melire@googlemail.com>+maintainer: Mekeor Melire <mekeor.melire@googlemail.com>+tested-with: GHC ==7.0.4+cabal-version: >= 1.6+build-type: Simple source-repository head+ type: darcs+ location: http://darcsden.com/mekeor/hascal+++source-repository head type: git location: git://github.com/MekeorMelire/hascal.git @@ -29,6 +33,7 @@ build-depends: base >2 && <5, numbers >= 3000 exposed-modules: Hascal ghc-options: -Wall+ executable hascal build-depends: base >2 && <5, numbers >= 3000