Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checkpoint #3

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cypher.clsp
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
(include cypher/standards/coin.clsp)
(include cypher/standards/conditions.clsp)
)
; mega-include file "include everything"
stmharry marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions cypher/condition_codes.clsp
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@
(defconstant ASSERT_BEFORE_HEIGHT_RELATIVE 86)
(defconstant ASSERT_BEFORE_HEIGHT_ABSOLUTE 87)
)
;; looks reasonable
46 changes: 25 additions & 21 deletions cypher/constants.clsp
Original file line number Diff line number Diff line change
@@ -1,39 +1,42 @@
(
(defconstant cypher.constants.NIL ())
(defconstant cypher.constants.NIL ()) ; note that `()` and `0` are equivalent
stmharry marked this conversation as resolved.
Show resolved Hide resolved
(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
stmharry marked this conversation as resolved.
Show resolved Hide resolved

(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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh so #c is identical to plain c?


(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
stmharry marked this conversation as resolved.
Show resolved Hide resolved
(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)

;; 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?
stmharry marked this conversation as resolved.
Show resolved Hide resolved
(defconstant cf.NIL ())
(defconstant cf.ZERO 0)
(defconstant cf.ONE 1)
Expand Down Expand Up @@ -66,3 +69,4 @@
(defconstant cf.ARITHMETIC_SHIFT ash)
(defconstant cf.LOGICAL_SHIFT lsh)
)
;; looks reasonable
6 changes: 6 additions & 0 deletions cypher/fracmath.clsp
Original file line number Diff line number Diff line change
@@ -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.
;
Expand Down
11 changes: 10 additions & 1 deletion cypher/hashlib.clsp
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅


(defconstant ONE#cypher.constants.ONE 1)
(defconstant TWO#cypher.constants.TWO 2)
Expand Down Expand Up @@ -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

stmharry marked this conversation as resolved.
Show resolved Hide resolved
(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
Expand Down Expand Up @@ -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!
7 changes: 6 additions & 1 deletion cypher/itertools.clsp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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.
22 changes: 12 additions & 10 deletions cypher/logexpmath.clsp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
27 changes: 27 additions & 0 deletions cypher/macros.clsp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. We can have two includes: (include cypher.clib) and (include cypher@dev.clib)

(defmacro @cypher.macros.assert@debug args
;; Assert a series of statements with debugging message.
;
Expand Down Expand Up @@ -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))
Expand All @@ -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))
Expand All @@ -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)))
Expand All @@ -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)))
Expand All @@ -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
14 changes: 12 additions & 2 deletions cypher/math.clsp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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
Expand Down Expand Up @@ -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)
)
)
Expand All @@ -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)))
Expand Down Expand Up @@ -168,3 +177,4 @@
(defmacro %cf.str args (c %cypher.math.str args))
(defmacro cf.str args (c cypher.math.str args))
)
;; looks good