From 5d2e7ad516ea5bd2903a310fcc091b5483addc8f Mon Sep 17 00:00:00 2001 From: Richard Kiss Date: Wed, 26 Apr 2023 17:29:28 -0700 Subject: [PATCH] checkpoint --- cypher.clsp | 1 + cypher/condition_codes.clsp | 1 + cypher/constants.clsp | 46 ++++++++++++++++++++----------------- cypher/fracmath.clsp | 6 +++++ cypher/hashlib.clsp | 11 ++++++++- cypher/itertools.clsp | 7 +++++- cypher/logexpmath.clsp | 22 ++++++++++-------- cypher/macros.clsp | 27 ++++++++++++++++++++++ cypher/math.clsp | 14 +++++++++-- 9 files changed, 100 insertions(+), 35 deletions(-) diff --git a/cypher.clsp b/cypher.clsp index d7d0d23..ff935ca 100644 --- a/cypher.clsp +++ b/cypher.clsp @@ -11,3 +11,4 @@ (include cypher/standards/coin.clsp) (include cypher/standards/conditions.clsp) ) +; mega-include file "include everything" \ No newline at end of file diff --git a/cypher/condition_codes.clsp b/cypher/condition_codes.clsp index 88caa6b..92dee18 100644 --- a/cypher/condition_codes.clsp +++ b/cypher/condition_codes.clsp @@ -55,3 +55,4 @@ (defconstant ASSERT_BEFORE_HEIGHT_RELATIVE 86) (defconstant ASSERT_BEFORE_HEIGHT_ABSOLUTE 87) ) +;; looks reasonable \ No newline at end of file diff --git a/cypher/constants.clsp b/cypher/constants.clsp index 8a4fbc2..597104a 100644 --- a/cypher/constants.clsp +++ b/cypher/constants.clsp @@ -1,32 +1,33 @@ ( - (defconstant cypher.constants.NIL ()) + (defconstant cypher.constants.NIL ()) ; note that `()` and `0` are equivalent (defconstant cypher.constants.ZERO 0) (defconstant cypher.constants.ONE 1) (defconstant cypher.constants.TWO 2) - (defconstant cypher.constants.ONE_2 100) - (defconstant cypher.constants.ONE_3 1000) - (defconstant cypher.constants.ONE_6 1000000) - (defconstant cypher.constants.ONE_9 1000000000) - (defconstant cypher.constants.ONE_12 1000000000000) + (defconstant cypher.constants.ONE_2 100) ;; consider hundred? Or `TEN_POW_2`? + (defconstant cypher.constants.ONE_3 1000) ;; thousand? Or `TEN_POW_3`? + (defconstant cypher.constants.ONE_6 1000000) ; million/TEN_POW_6 + (defconstant cypher.constants.ONE_9 1000000000) ; billion/TEN_POW_9 + (defconstant cypher.constants.ONE_12 1000000000000) ; trillion/TEN_POW_12 - (defconstant cypher.constants.CONS c) - (defconstant cypher.constants.FIRST f) - (defconstant cypher.constants.REST r) - (defconstant cypher.constants.LISTP l) + (defconstant cypher.constants.CONS #c) + (defconstant cypher.constants.FIRST #f) + (defconstant cypher.constants.REST #r) + (defconstant cypher.constants.LISTP #l) ;; the `#` emphasizes that it's a keyword - (defconstant cypher.constants.APPLY a) - (defconstant cypher.constants.IF i) - (defconstant cypher.constants.RAISE x) - (defconstant cypher.constants.EQUAL =) - (defconstant cypher.constants.GT >) - (defconstant cypher.constants.BYTES_GT >s) + ;; maybe consider `cypher.opcode` instead of `cypher.constants` for the opcodes + (defconstant cypher.constants.APPLY #a) + (defconstant cypher.constants.IF #i) + (defconstant cypher.constants.RAISE #x) + (defconstant cypher.constants.EQUAL #=) + (defconstant cypher.constants.GT #>) + (defconstant cypher.constants.BYTES_GT #>s) - (defconstant cypher.constants.QUOTE q) + (defconstant cypher.constants.QUOTE #q) - (defconstant cypher.constants.PLUS +) - (defconstant cypher.constants.MINUS -) - (defconstant cypher.constants.MUL *) - (defconstant cypher.constants.DIV /) + (defconstant cypher.constants.PLUS #+) + (defconstant cypher.constants.MINUS #-) + (defconstant cypher.constants.MUL #*) + (defconstant cypher.constants.DIV #/) (defconstant cypher.constants.ARITHMETIC_SHIFT ash) (defconstant cypher.constants.LOGICAL_SHIFT lsh) @@ -34,6 +35,8 @@ ;; Exports ; TODO(stmharry): is there any way around this? + ;; these seem redundant. I'm sure there's a reason, but I'm not sure what it is + ;; maybe the idea is `cf` is the export level? (defconstant cf.NIL ()) (defconstant cf.ZERO 0) (defconstant cf.ONE 1) @@ -66,3 +69,4 @@ (defconstant cf.ARITHMETIC_SHIFT ash) (defconstant cf.LOGICAL_SHIFT lsh) ) +;; looks reasonable \ No newline at end of file diff --git a/cypher/fracmath.clsp b/cypher/fracmath.clsp index d78fc9a..6f45ae5 100644 --- a/cypher/fracmath.clsp +++ b/cypher/fracmath.clsp @@ -1,6 +1,12 @@ ( ;; Fractions. +;; maybe an "unsafe" & shorter version of this which assumes `denom` > 0? +;; there is a differentiation, in general between "trusted" and "untrusted" data +;; (Never mind, I see you've done this.) +;; also, I wonder if negative denominator is okay (obviously zero isn't). I'll keep +;; this question in mind as I read. + (defun-inline %cypher.fracmath.Frac (numer denom) ;; Fraction representation. ; diff --git a/cypher/hashlib.clsp b/cypher/hashlib.clsp index b957b4a..806b085 100644 --- a/cypher/hashlib.clsp +++ b/cypher/hashlib.clsp @@ -1,7 +1,7 @@ ;; Hashing library. ( - ; name mingling to be compatible with curry-and-treehash.clinc + ; name mangling to be compatible with curry-and-treehash.clinc (defconstant ONE#cypher.constants.ONE 1) (defconstant TWO#cypher.constants.TWO 2) @@ -89,6 +89,13 @@ ) ) + ;; note that this function requires the parameter hashes to be reversed + ;; this is because I was brain-dead when I wrote this and thought it + ;; was more efficient to have the parameters reversed. Of course, it is not, + ;; but it is much harder to reason about. I've since written a version that is + ;; not stupid, which should be used going forward. It's at + ;; https://github.com/Chia-Network/chia-blockchain/blob/main/chia/wallet/puzzles/curry.clib + (defmacro cypher.hashlib.build-curry-list args (c build-curry-list#cypher.hashlib.build-curry-list args)) (defun build-curry-list#cypher.hashlib.build-curry-list @@ -186,3 +193,5 @@ (c cypher.hashlib.puzzle-hash-of-curried-function args)) (defmacro cf.calculate-coin-id args (c cypher.hashlib.calculate-coin-id args)) ) + +;; this looks reasonable. A lot of necessary name tweaks and hacks to get it to compile the standard way. Lots of hard work! \ No newline at end of file diff --git a/cypher/itertools.clsp b/cypher/itertools.clsp index a3673c1..3d3f97d 100644 --- a/cypher/itertools.clsp +++ b/cypher/itertools.clsp @@ -41,6 +41,7 @@ ) cypher.constants.NIL ) + ;; I wonder if it would make sense to not use `chain-two` but rather put both loops in here ) (defmacro @cypher.itertools.chain iterables @@ -79,7 +80,7 @@ ; func: Function symbol name. ; args: List of arguments to apply func on. ; agg_init: Initial value. - ; global_args: Global arguments. + ; global_args: Global arguments. ;; consider calling it `context` ; ; Returns: ; A reduced value. @@ -102,3 +103,7 @@ (defmacro cf.map args (c cypher.itertools.map args)) (defmacro cf.reduce args (c cypher.itertools.reduce args)) ) +;; looks good +;; I spoke to Bram recently about his wish list for iters, and he mentioned several properties that could be +;; chosen or not for a loop: filter, map, count, reduce, max, min, flatten, match. I'm going to do some +;; more thinking about this though, maybe with macros. \ No newline at end of file diff --git a/cypher/logexpmath.clsp b/cypher/logexpmath.clsp index 8aa7192..05aa382 100644 --- a/cypher/logexpmath.clsp +++ b/cypher/logexpmath.clsp @@ -7,16 +7,18 @@ (defconstant cypher.logexpmath.constants.LN_72_A6 29444659034920256478884744064437645965741631810494) (defconstant cypher.logexpmath.constants.LN_72_A5 372892036554861672118798300772074960) (defconstant cypher.logexpmath.constants.LN_72_A4 41963470485121714839508006980) - (defconstant cypher.logexpmath.constants.LN_72_A3 14077176084848423785660528) - (defconstant cypher.logexpmath.constants.LN_72_A2 257832473743208563546842) - (defconstant cypher.logexpmath.constants.LN_72_A1 34893830861633635945704) - (defconstant cypher.logexpmath.constants.LN_72_A0 12836722997708609710783) - (defconstant cypher.logexpmath.constants.LN_72_AN1 7785866068348536395565) - (defconstant cypher.logexpmath.constants.LN_72_AN2 6063638590918920402555) - (defconstant cypher.logexpmath.constants.LN_72_AN3 5351142274878367833325) - (defconstant cypher.logexpmath.constants.LN_72_AN4 5026932953994157872561) - - (defconstant cypher.logexpmath.constants.LN_72_EXPONENT_UPPER_BOUND 2417556491324078996586496) + (defconstant cypher.logexpmath.constants.LN_72_A3 14077176084848423785660528) Decimal.exp(Decimal(pow(2, 3))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_A2 257832473743208563546842) ; Decimal.exp(Decimal(pow(2, 2))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_A1 34893830861633635945704) ; Decimal.exp(Decimal(pow(2, 1))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_A0 12836722997708609710783) ; Decimal.exp(Decimal(pow(2, 0))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_AN1 7785866068348536395565) ; Decimal.exp(Decimal(pow(2, -1))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_AN2 6063638590918920402555) ; Decimal.exp(Decimal(pow(2, -2))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_AN3 5351142274878367833325) ; Decimal.exp(Decimal(pow(2, -3))) * (1 << 72) + (defconstant cypher.logexpmath.constants.LN_72_AN4 5026932953994157872561) ; Decimal.exp(Decimal(pow(2, -4))) * (1 << 72) + +;; for LN_72_AN1 I get `Decimal('7785866068348536395565.996014')`. Not sure if it makes sense to round this up to 7785866068348536395566 + + (defconstant cypher.logexpmath.constants.LN_72_EXPONENT_UPPER_BOUND 2417556491324078996586496) ;; not sure what this is (defun-inline cypher.logexpmath.constants.USE_LN_128_UPPER_BOUND () (%cypher.fracmath.Frac@unsafe 11 10)) (defun-inline cypher.logexpmath.constants.USE_LN_128_LOWER_BOUND () (%cypher.fracmath.Frac@unsafe 9 10)) diff --git a/cypher/macros.clsp b/cypher/macros.clsp index 5c76690..7728ea2 100644 --- a/cypher/macros.clsp +++ b/cypher/macros.clsp @@ -14,6 +14,9 @@ ) ) + ;; this is very clever + ;; I wonder if it makes sense to have "profiles" like rust does, so we can get debug messages + ;; back from asserts in DEBUG mode, but have them stripped out for RELEASE mode (defmacro @cypher.macros.assert@debug args ;; Assert a series of statements with debugging message. ; @@ -54,6 +57,10 @@ ; ; Usage: (and cond1 cond2 ...) ; Taken from chia/wallet/puzzles/utility_macros.clib. + ;; the other one is probably better as it terminates on the last condition rather + ;; than exposing a lone `1` + ;; the only advantage this one has is it doesn't choke on the (rather useless) `(and)` + ;; case. It could be written to support it, and then this `v2` version deprecated. (if args (qq (if (unquote (f args)) @@ -72,6 +79,17 @@ ; Note that this is different from `list` as there is not a `()` in the end. ; This function is particularly useful when concatenating atoms to an existing list. + ;; this is a good idea. I do note that I consider `concat` to be a function that + ;; operates on two lists, flattening them into one. Maybe a good name for this + ;; is `prelist` (a portmanteau of "prefix list"). + ;; So `(prelist A B C)` => `(c A (c B C))` + ;; Another good thing about `prelist` is I've never seen it before, so it doesn't have + ;; any preconceived notions. + ;; Another option is `multicons` or `mcons` (for "multiple cons") + ;; ChatGPT doesn't seem to be aware of an existing library function that does this in + ;; lisp nor scheme (although its confusion about `list*` suggests it's not a total + ;; lisp wizard) + (if (r args) (qq (c (unquote (f args)) @@ -86,6 +104,11 @@ ; ; Usage: (if-elif cond1 result1 cond2 result2 ... default) + ;; Bram calls this "continued if" and has requested it + ;; It's interesting that it actually is a generalization of `if`. It might + ;; make sense to simply change `if` in the base language (which is implemented as + ;; built-in macro) to allow for this. + (if (r args) (qq (if (unquote (f args)) (unquote (f (r args))) @@ -99,6 +122,9 @@ ;; Nested if-else statements with con'ed statements. ; ; Usage: (switch (cond1 . result1) (cond2 . result2) ... default) + ;; I think this is called `cond` in many lisps + ;; not sure if we actually want `(cond1 . result1)` vs `(cond1 result1)` + ;; would save the user typing a lot of dots for no real benefit (if (r args) (qq (if (unquote (f (f args))) @@ -119,3 +145,4 @@ (defmacro @cf.if-elif args (c @cypher.macros.if-elif args)) (defmacro @cf.switch args (c @cypher.macros.switch args)) ) +;; looks good \ No newline at end of file diff --git a/cypher/math.clsp b/cypher/math.clsp index dab07fc..deaaf16 100644 --- a/cypher/math.clsp +++ b/cypher/math.clsp @@ -11,21 +11,29 @@ ;; Rounding to even or odd. (defun-inline %cypher.math.round-down-to-even (var) + ;; how about `(logand var -2)` + ;; seems cheaper in `brun` for small values. Haven't tried large ones (if (logand var 1) (- var 1) var)) (defun cypher.math.round-down-to-even (var) (%cypher.math.round-down-to-even var)) (defun-inline %cypher.math.round-down-to-odd (var) + ;; maybe `(logior (- var 1) 1)` + ;; this seems more expensive (if (logand var 1) var (- var 1))) (defun cypher.math.round-down-to-odd (var) (%cypher.math.round-down-to-odd var)) (defun-inline %cypher.math.round-up-to-even (var) + ;; maybe `(logand (+ 1 var) -2)` + ;; my tests suggest it's more expensive to run than the `if` form, although the code + ;; is smaller (if (logand var 1) (+ var 1) var)) (defun cypher.math.round-up-to-even (var) (%cypher.math.round-up-to-even var)) (defun-inline %cypher.math.round-up-to-odd (var) + ;; `(logior var 1)` (if (logand var 1) var (+ var 1))) (defun cypher.math.round-up-to-odd (var) (%cypher.math.round-up-to-odd var)) @@ -49,6 +57,7 @@ (%cypher.math.abs var)) ;; Multiply var by fraction (numer / denom). + ;; seeing this return an int instead of a fraction surprised me (defun-inline %cypher.math.mul-frac (var frac) (%cypher.math.div @@ -104,7 +113,7 @@ ) (defun-inline %cypher.math.pow (base exponent) (@cypher.macros.assert - (not (> 0 exponent)) + (> exponent 0) ;; we don't need `not`, and exponent == 0 is okay (--cypher.math.pow base exponent) ) ) @@ -125,7 +134,7 @@ (any (> var 0) (> decimals 0) (= decimals 0)) (concat (--cypher.math.str - (%cypher.math.div var 10) + (%cypher.math.div var 10) ;; you should be able to do this with a single `divmod` per loop (- decimals 1) ) (+ 48 (r (divmod var 10))) @@ -168,3 +177,4 @@ (defmacro %cf.str args (c %cypher.math.str args)) (defmacro cf.str args (c cypher.math.str args)) ) +;; looks good