tdrdobbs_examples.nim 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. discard """
  2. output: '''108
  3. 11 -1 1936
  4. 0.4
  5. true
  6. truefalse'''
  7. """
  8. proc `++`(x: var int; y: int = 1; z: int = 0) =
  9. x = x + y + z
  10. var g = 70
  11. ++g
  12. g ++ 7
  13. g.`++`(10, 20)
  14. echo g
  15. #let lv = stdin.readline
  16. #var vv = stdin.readline
  17. #vv = "abc" # valid, reassignment allowed
  18. #lv = "abc" # fails at compile time
  19. #proc square(x: int): int = x*x
  20. template square(x: int): int =
  21. # ensure 'x' is only evaluated once:
  22. let y = x
  23. y * y
  24. proc mostSignificantBit(n: int): int =
  25. # naive algorithm:
  26. var n = n
  27. while n != 0:
  28. n = n shr 1
  29. result += 1
  30. result -= 1
  31. const msb3999 = mostSignificantBit(3999)
  32. echo msb3999, " ", mostSignificantBit(0), " ", square(44)
  33. proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] =
  34. result = @[] # @[] constructs the empty seq
  35. for x in a:
  36. if predicate(x): result.add(x)
  37. proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] =
  38. newSeq(result, a.len)
  39. for i in 0 .. <a.len: result[i] = fn(a[i])
  40. type
  41. FormulaKind = enum
  42. fkVar, ## element is a variable like 'X'
  43. fkLit, ## element is a literal like 0.1
  44. fkAdd, ## element is an addition operation
  45. fkMul, ## element is a multiplication operation
  46. fkExp ## element is an exponentiation operation
  47. type
  48. Formula = ref object
  49. case kind: FormulaKind
  50. of fkVar: name: string
  51. of fkLit: value: float
  52. of fkAdd, fkMul, fkExp: left, right: Formula
  53. from math import pow
  54. proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
  55. case n.kind
  56. of fkVar: varToVal(n.name)
  57. of fkLit: n.value
  58. of fkAdd: evaluate(n.left, varToVal) + evaluate(n.right, varToVal)
  59. of fkMul: evaluate(n.left, varToVal) * evaluate(n.right, varToVal)
  60. of fkExp: pow(evaluate(n.left, varToVal), evaluate(n.right, varToVal))
  61. echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
  62. proc isPolyTerm(n: Formula): bool =
  63. n.kind == fkMul and n.left.kind == fkLit and (let e = n.right;
  64. e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
  65. proc isPolynomial(n: Formula): bool =
  66. isPolyTerm(n) or
  67. (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
  68. let myFormula = Formula(kind: fkMul,
  69. left: Formula(kind: fkLit, value: 2.0),
  70. right: Formula(kind: fkExp,
  71. left: Formula(kind: fkVar, name: "x"),
  72. right: Formula(kind: fkLit, value: 5.0)))
  73. echo isPolyTerm(myFormula)
  74. proc pat2kind(pattern: string): FormulaKind =
  75. case pattern
  76. of "^": fkExp
  77. of "*": fkMul
  78. of "+": fkAdd
  79. of "x": fkVar
  80. of "c": fkLit
  81. else: fkVar # no error reporting for reasons of simplicity
  82. import macros
  83. proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} =
  84. template `@`(current, field: untyped): untyped =
  85. newDotExpr(current, newIdentNode(astToStr(field)))
  86. template `==@`(n, pattern: untyped): untyped =
  87. newCall("==", n@kind, newIdentNode($pat2kind($pattern.ident)))
  88. case pattern.kind
  89. of CallNodes:
  90. result = newCall("and",
  91. n ==@ pattern[0],
  92. matchAgainst(n@left, pattern[1]))
  93. if pattern.len == 3:
  94. result = newCall("and", result.copy,
  95. matchAgainst(n@right, pattern[2]))
  96. of nnkIdent:
  97. result = n ==@ pattern
  98. of nnkPar:
  99. result = matchAgainst(n, pattern[0])
  100. else:
  101. error "invalid pattern"
  102. macro `=~` (n: Formula, pattern: untyped): bool =
  103. result = matchAgainst(n, pattern)
  104. proc isPolyTerm2(n: Formula): bool = n =~ c * x^c
  105. echo isPolyTerm2(myFormula), isPolyTerm2(Formula(kind: fkLit, value: 0.7))