Advertisement
Guest User

Untitled

a guest
Dec 20th, 2014
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.66 KB | None | 0 0
  1. -- tries to implement integers using fold and a generalized notion of 'reduction' instead of
  2. -- utilizing recursion explicitly in all operations./
  3. -- maximum (reasonable) code reuse, information hiding and conciseness is emphasized through
  4. -- generalized mechanisms, particularly hiding the internal representation and avoiding excessive
  5. -- pattern matchings.
  6. -- integers are interpreted as distances from 0 on the negative or positive sides of the
  7. -- axis. 'reducing' (`fold` and `loop`) tries to (recursively) reach `Zero` which means
  8. -- either `suc` or `pred` depending on the sign (`bck`).
  9. module Z
  10.  
  11. -- an integer has a sign (P or N) and a distance from 0 (the Nat part with a little quirk*)
  12. -- *the little quirk:
  13. -- if `P n` == +n and `N n` == -n then both `P O` (+0) and `N O` (-0) would represent 0 which is terrible
  14. -- since this should be taken care of throughout the module so I got smart, heeded the elders
  15. -- advice and decided to interpret n to mean n+1 in `P n` and `N n`. this way `P 0` means +1 and `N 2` means -3.
  16. -- so far only `Cast Z Int instance`, `pred` and `suc` had to pay. other parts of the module are
  17. -- totally agnostic to this quirk which probably means it is the right approach.
  18. data Z = P Nat | N Nat | Zero
  19. data Sign = pos | neg | zro
  20.  
  21. -- picks an operation and performs it on `n` according to its sign and distance from 0
  22. -- this is a powerful abstraction since many functions could be defined over it
  23. total match : (n : Z) -> (zero : a) -> (positive : Nat->a) -> (negative : Nat->a) -> a
  24. match Zero zero _ _ = zero
  25. match (P n) _ positive _ = positive n
  26. match (N n) _ _ negative = negative n
  27.  
  28. -- same as `match` but works on Nats
  29. -- pay attention that input (`n`) comes last here
  30. -- because `nmatch` is used in situations that is more
  31. -- convenient with this arrangement
  32. total nmatch : (zero : a) -> (nonzero : Nat->a) -> (n:Nat) -> a
  33. nmatch zero _ O = zero
  34. nmatch _ nonzero (S k) = nonzero k
  35.  
  36. -- move left
  37. total pred : Z -> Z
  38. pred n = match n (N O) (nmatch Zero P) (N . S)
  39.  
  40. -- move right
  41. total suc : Z -> Z
  42. suc n = match n (P O) (P . S) (nmatch Zero N)
  43.  
  44. -- converts a constant of type `a` to a function that accepts a `b` and returns an `a`
  45. -- useful in places that expect a function but a simple value would suffice.
  46. -- parameters `a` and `b` make this mechanism very flexible.
  47. instance Cast a (b->a) where
  48. cast c = (x=>c)
  49.  
  50. -- sign of an integer
  51. total sgn : Z -> Sign
  52. sgn n = match n zro (cast pos) (cast neg) -- employs the above Cast to prevent writing (n=> ...)
  53.  
  54. -- distance from Zero as a positive `Z`. contrast with `match` arguments that receives the same thing as a `Nat`
  55. total abs : Z -> Z
  56. abs n = match n Zero P P
  57.  
  58. -- negation
  59. total ngt : Z -> Z
  60. ngt n = match n Zero N P
  61.  
  62. -- transforms `n` depending on its sign
  63. -- basically `match` but passes the whole `n` instead of it's distance, effectively
  64. -- removing duplication in such functions as `fwd` and `bck`
  65. total caseOnSgn : (n:Z) -> (zero:a) -> (positive : Z->a) -> (negative : Z->a) -> a
  66. caseOnSgn n zero positive negative = match n zero (positive . P) (negative . N)
  67.  
  68. -- move one number away from Zero
  69. total fwd : Z -> Z
  70. fwd n = caseOnSgn n Zero suc pred
  71.  
  72. -- move one number towards Zero
  73. -- since Zero is the base case for almost all functions operating on integers, this
  74. -- effectively defines the reducing mechanism for the whole Z as demonstrated in `fold`
  75. total bck : Z -> Z
  76. bck n = caseOnSgn n Zero pred suc
  77.  
  78. -- folding from Zero towards `n`
  79. -- uses `bck` instead of explicit pattern matching on `n` thus eliminating
  80. -- duplication , resulting in a more point-free style implementation
  81. %assert_total
  82. total fold : (i : Z) -> (f: Z->Z->Z) -> (n:Z) -> Z
  83. fold i _ Zero = i
  84. fold i f n = let acc = fold i f (bck n) in f acc n -- `acc` introduced for clarity
  85.  
  86. -- like fold but ignores the index
  87. -- useful in situations where the intermediate indices are irrelevant (`add`)
  88. loop : (i:Z) -> (f:Z->Z) -> (n:Z) -> Z
  89. loop i f n = fold i (acc,index=>f acc) n -- just discards the `index`
  90.  
  91. -- addition
  92. -- very simple and expressive interpretation of addition
  93. -- m+n means :
  94. -- moving `n` units to the right from `m` if `n` is positive
  95. -- moving `n` units to the left from `m` if `n` is negative
  96. -- or just `m` if `n` is Zero
  97. add : Z -> Z -> Z
  98. add n m = caseOnSgn m n (loop n suc) (loop n pred) -- `suc` : move to the right, `pred` : move to the left
  99.  
  100. -- subtraction
  101. -- n-m = n + (-m)
  102. sub : Z -> Z -> Z
  103. sub n m = add n (ngt m)
  104.  
  105. instance Cast Z Int where
  106. cast Zero = 0
  107. cast (P k) = cast {to=Int} (S k) -- (S k) => the little quirk, see definition of `Z`
  108. cast (N k) = -1 * cast {to=Int} (S k)
  109.  
  110. instance Show Z where
  111. show n = show $ cast {to=Int} n
  112.  
  113. instance Show Sign where
  114. show zro = "0"
  115. show pos = "+"
  116. show neg = "-"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement