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
|
discard """
output: '''108
11 -1 1936
0.4
true
truefalse'''
"""
proc `++`(x: var int; y: int = 1; z: int = 0) =
x = x + y + z
var g = 70
++g
g ++ 7
g.`++`(10, 20)
echo g
#let lv = stdin.readline
#var vv = stdin.readline
#vv = "abc" # valid, reassignment allowed
#lv = "abc" # fails at compile time
#proc square(x: int): int = x*x
template square(x: int): int =
# ensure 'x' is only evaluated once:
let y = x
y * y
proc mostSignificantBit(n: int): int =
# naive algorithm:
var n = n
while n != 0:
n = n shr 1
result += 1
result -= 1
const msb3999 = mostSignificantBit(3999)
echo msb3999, " ", mostSignificantBit(0), " ", square(44)
proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] =
result = @[] # @[] constructs the empty seq
for x in a:
if predicate(x): result.add(x)
proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] =
newSeq(result, a.len)
for i in 0 .. <a.len: result[i] = fn(a[i])
type
FormulaKind = enum
fkVar, ## element is a variable like 'X'
fkLit, ## element is a literal like 0.1
fkAdd, ## element is an addition operation
fkMul, ## element is a multiplication operation
fkExp ## element is an exponentiation operation
type
Formula = ref object
case kind: FormulaKind
of fkVar: name: string
of fkLit: value: float
of fkAdd, fkMul, fkExp: left, right: Formula
from math import pow
proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
case n.kind
of fkVar: varToVal(n.name)
of fkLit: n.value
of fkAdd: evaluate(n.left, varToVal) + evaluate(n.right, varToVal)
of fkMul: evaluate(n.left, varToVal) * evaluate(n.right, varToVal)
of fkExp: pow(evaluate(n.left, varToVal), evaluate(n.right, varToVal))
echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
proc isPolyTerm(n: Formula): bool =
n.kind == fkMul and n.left.kind == fkLit and (let e = n.right;
e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
proc isPolynomial(n: Formula): bool =
isPolyTerm(n) or
(n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
let myFormula = Formula(kind: fkMul,
left: Formula(kind: fkLit, value: 2.0),
right: Formula(kind: fkExp,
left: Formula(kind: fkVar, name: "x"),
right: Formula(kind: fkLit, value: 5.0)))
echo isPolyTerm(myFormula)
proc pat2kind(pattern: string): FormulaKind =
case pattern
of "^": fkExp
of "*": fkMul
of "+": fkAdd
of "x": fkVar
of "c": fkLit
else: fkVar # no error reporting for reasons of simplicity
import macros
proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} =
template `@`(current, field: expr): expr =
newDotExpr(current, newIdentNode(astToStr(field)))
template `==@`(n, pattern: expr): expr =
newCall("==", n@kind, newIdentNode($pat2kind($pattern.ident)))
case pattern.kind
of CallNodes:
result = newCall("and",
n ==@ pattern[0],
matchAgainst(n@left, pattern[1]))
if pattern.len == 3:
result = newCall("and", result.copy,
matchAgainst(n@right, pattern[2]))
of nnkIdent:
result = n ==@ pattern
of nnkPar:
result = matchAgainst(n, pattern[0])
else:
error "invalid pattern"
macro `=~` (n: Formula, pattern: expr): bool =
result = matchAgainst(n, pattern)
proc isPolyTerm2(n: Formula): bool = n =~ c * x^c
echo isPolyTerm2(myFormula), isPolyTerm2(Formula(kind: fkLit, value: 0.7))
|