Skip to content

Commit 6e6c795

Browse files
author
Kirill Saksin
committed
Initial commit (and most likely last one)
0 parents  commit 6e6c795

16 files changed

+541
-0
lines changed

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.stack-work
2+
.history

Diff for: LICENSE

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Copyright Author name here (c) 2017
2+
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above
12+
copyright notice, this list of conditions and the following
13+
disclaimer in the documentation and/or other materials provided
14+
with the distribution.
15+
16+
* Neither the name of Author name here nor the names of other
17+
contributors may be used to endorse or promote products derived
18+
from this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Diff for: README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# calc
2+
3+
Experiments in Haskell: command line calculator.
4+
5+
## Usage
6+
7+
```bash
8+
$ stack build
9+
$ stack exec calc-exe
10+
```
11+
12+
### As library
13+
14+
```haskell
15+
import Term
16+
17+
computed = eval $ Sum (ValueF 10) (Pi)
18+
```
19+
20+
21+
```haskell
22+
import Term
23+
import Text.Parsec
24+
25+
parseCalculation text = fmap toExpr $ parse termsP "my calc" text
26+
execParsed parsed = fmap eval parsed
27+
```
28+

Diff for: Setup.hs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

Diff for: app/Main.hs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Main where
2+
3+
import CalcRepl
4+
5+
import Control.Monad
6+
import System.IO
7+
import System.Console.Repline
8+
import Control.Monad.Trans
9+
10+
main :: IO ()
11+
main = evalRepl "> " (\x -> liftIO $ replBody x) [] (Word $ const $ return []) (return ())

Diff for: calc.cabal

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: calc
2+
version: 0.1.0.0
3+
-- synopsis:
4+
-- description:
5+
homepage: https://github.com/saksmt/experimental-hs-calc#readme
6+
license: BSD3
7+
license-file: LICENSE
8+
author: Kirill Saksin
9+
maintainer: [email protected]
10+
copyright: 2017 Kirill Saksin
11+
category: Console
12+
build-type: Simple
13+
extra-source-files: README.md
14+
cabal-version: >=1.10
15+
16+
library
17+
hs-source-dirs: src
18+
exposed-modules: Term, Expr, CalcRepl
19+
other-modules: Term.Def, Term.Parser, Term.ToExpr, Util.Predicate, Util.List
20+
build-depends: base >= 4.7 && < 5
21+
, parsec
22+
, parsec-numbers
23+
, derive
24+
default-language: Haskell2010
25+
26+
executable calc-exe
27+
hs-source-dirs: app
28+
main-is: Main.hs
29+
ghc-options: -threaded -rtsopts -with-rtsopts=-N
30+
build-depends: base
31+
, calc
32+
, repline
33+
, mtl
34+
default-language: Haskell2010
35+
36+
test-suite calc-test
37+
type: exitcode-stdio-1.0
38+
hs-source-dirs: test
39+
main-is: Spec.hs
40+
build-depends: base
41+
, calc
42+
ghc-options: -threaded -rtsopts -with-rtsopts=-N
43+
default-language: Haskell2010
44+
45+
source-repository head
46+
type: git
47+
location: https://github.com/saksmt/experimental-hs-calc

Diff for: src/CalcRepl.hs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module CalcRepl where
2+
3+
import Term
4+
import Expr
5+
import Text.Parsec
6+
7+
import Control.Monad
8+
import System.IO
9+
10+
replBody raw = either ((hPutStrLn stderr) . show) print $ fmap (eval . toExpr) $ parse termsP "(interactive)" raw
11+

Diff for: src/Expr.hs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{-# LANGUAGE TemplateHaskell #-}
2+
3+
module Expr(Expr(..), eval) where
4+
5+
import Data.List(findIndex)
6+
import Data.Fixed(mod')
7+
8+
data Expr = ValueF Double
9+
| Sum Expr Expr
10+
| Diff Expr Expr
11+
| Pow Expr Expr
12+
| Mul Expr Expr
13+
| Div Expr Expr
14+
| Neg Expr
15+
| Mod Expr Expr
16+
| Round Expr
17+
| Floor Expr
18+
| Abs Expr
19+
| Sin Expr
20+
| Cos Expr
21+
| Tan Expr
22+
| ASin Expr
23+
| ACos Expr
24+
| ATan Expr
25+
| Pi
26+
| Sqrt Expr
27+
| Log Expr Expr
28+
| Exp Expr
29+
| E
30+
| Ceil Expr deriving (Show)
31+
32+
eval :: Expr -> Double
33+
eval (ValueF v) = v
34+
eval (Sum a b) = eval a + eval b
35+
eval (Diff a b) = eval a - eval b
36+
eval (Pow a b) = eval a ** eval b
37+
eval (Mul a b) = eval a * eval b
38+
eval (Neg v) = - eval v
39+
eval (Mod a b) = eval a `mod'` eval b
40+
eval (Round v) = fromIntegral $ round $ eval v
41+
eval (Floor v) = fromIntegral $ floor $ eval v
42+
eval (Ceil v) = fromIntegral $ ceiling $ eval v
43+
eval (Div a b) = eval a / eval b
44+
eval (Abs v) = abs $ eval v
45+
eval (Sin v) = sin $ eval v
46+
eval (Cos v) = cos $ eval v
47+
eval (Tan v) = tan $ eval v
48+
eval (ASin v) = asin $ eval v
49+
eval (ACos v) = acos $ eval v
50+
eval (ATan v) = atan $ eval v
51+
eval (Pi) = pi
52+
eval (Sqrt v) = sqrt $ eval v
53+
eval (Log b e) = eval b `logBase` eval e
54+
eval (Exp v) = exp $ eval v
55+
eval (E) = exp 1
56+

Diff for: src/Term.hs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module Term
2+
( termsP
3+
, toExpr
4+
, Term
5+
) where
6+
7+
import Term.Parser(termsP)
8+
import Term.Def(Term)
9+
import Term.ToExpr(toExpr)
10+

Diff for: src/Term/Def.hs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{-# LANGUAGE TemplateHaskell #-}
2+
3+
module Term.Def
4+
( Term(..)
5+
, isSumT
6+
, isDiffT
7+
, isPowT
8+
, isMulT
9+
, isDivT
10+
, isModT
11+
, isNegT
12+
, isPrioT
13+
, isRoundT
14+
, isFloorT
15+
, isCeilT
16+
, isAbsT
17+
, isSinT
18+
, isCosT
19+
, isTanT
20+
, isASinT
21+
, isACosT
22+
, isATanT
23+
, isPiT
24+
, isSqrtT
25+
, isLogT
26+
, isExpT
27+
, isET
28+
) where
29+
30+
import Data.DeriveTH
31+
import Data.Derive.Is
32+
33+
data Term = ValueT Double
34+
| SumT
35+
| DiffT
36+
| PowT
37+
| MulT
38+
| DivT
39+
| ModT
40+
| NegT Term
41+
| PrioT [Term]
42+
| RoundT [Term]
43+
| FloorT [Term]
44+
| AbsT [Term]
45+
| SinT [Term]
46+
| CosT [Term]
47+
| TanT [Term]
48+
| ASinT [Term]
49+
| ACosT [Term]
50+
| ATanT [Term]
51+
| PiT
52+
| SqrtT [Term]
53+
| LogT [Term] [Term]
54+
| ExpT [Term]
55+
| ET
56+
| CeilT [Term] deriving (Show)
57+
58+
$( derive makeIs ''Term )
59+

Diff for: src/Term/Parser.hs

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
module Term.Parser
2+
( termsP
3+
) where
4+
5+
import Text.Parsec
6+
import Text.Parsec.String
7+
import Text.ParserCombinators.Parsec.Number(floating2)
8+
9+
import Control.Monad
10+
import Data.Maybe(isJust)
11+
12+
import Term.Def(Term(..))
13+
14+
eP = spaces >> oneOf "eE" >> spaces >> return ET
15+
piP = spaces >> (string "PI" <|> string "pi" <|> string "Pi" <|> string "π") >> spaces >> return PiT
16+
valueP = do
17+
spaces
18+
v <- floating2 True
19+
spaces
20+
return $ ValueT v
21+
22+
funP :: String -> ([Term] -> Term) -> Parser Term
23+
funP functionName constructor = do
24+
spaces
25+
string functionName
26+
spaces
27+
char '('
28+
spaces
29+
terms <- termsP <?> "expression or value"
30+
spaces
31+
char ')'
32+
spaces
33+
return $ constructor terms
34+
35+
absMP = do
36+
spaces
37+
char '|'
38+
spaces
39+
terms <- termsP <?> "expression or value"
40+
spaces
41+
char '|'
42+
spaces
43+
return $ AbsT terms
44+
45+
logP = do
46+
spaces
47+
string "log"
48+
spaces
49+
char '('
50+
base <- termsP
51+
spaces
52+
char ','
53+
spaces
54+
exponent <- termsP
55+
spaces
56+
char ')'
57+
spaces
58+
return $ LogT base exponent
59+
60+
binaryP :: Char -> Term -> Parser Term
61+
binaryP sign v = do
62+
spaces
63+
char sign
64+
spaces
65+
return v
66+
67+
sumP = binaryP '+' SumT
68+
difP = binaryP '-' DiffT
69+
powP = binaryP '^' PowT
70+
mulP = (binaryP '*' MulT) <|> (binaryP '×' MulT) <|> try (binaryP 'x' MulT)
71+
divP = (binaryP '/' DivT) <|> (binaryP '÷' DivT)
72+
modP = binaryP '%' ModT
73+
74+
floorP = funP "floor" FloorT
75+
ceilP = funP "ceil" CeilT
76+
prioP = funP "" PrioT
77+
roundP = funP "round" RoundT
78+
absP = funP "abs" AbsT
79+
sinP = funP "sin" SinT
80+
cosP = funP "cos" CosT
81+
tanP = funP "tan" TanT
82+
asinP = funP "asin" ASinT
83+
acosP = funP "acos" ACosT
84+
atanP = funP "atan" ATanT
85+
sqrtP = funP "sqrt" SqrtT
86+
expP = funP "exp" ExpT
87+
88+
opP = sumP
89+
<|> difP
90+
<|> powP
91+
<|> mulP
92+
<|> divP
93+
<|> modP
94+
95+
_unaryP = valueP
96+
<|> try piP
97+
<|> try expP
98+
<|> try eP
99+
<|> try prioP
100+
<|> try ceilP
101+
<|> floorP
102+
<|> roundP
103+
<|> absMP
104+
<|> try absP
105+
<|> try sinP
106+
<|> try cosP
107+
<|> tanP
108+
<|> try asinP
109+
<|> try acosP
110+
<|> try atanP
111+
<|> try sqrtP
112+
<|> logP
113+
114+
unaryP = do
115+
s <- optionMaybe $ char '-'
116+
v <- _unaryP
117+
if isJust s then
118+
return $ NegT v
119+
else
120+
return v
121+
122+
afterUnaryP = do
123+
o <- opP <?> "operator"
124+
a <- unaryP <?> "expression or value"
125+
return [o, a]
126+
127+
termsP = do
128+
u <- unaryP <?> "expression or value"
129+
a <- many afterUnaryP
130+
return $ u:(join a)
131+

0 commit comments

Comments
 (0)