Skip to content

Instantly share code, notes, and snippets.

@bhb
bhb / ex.clj
Created February 13, 2018 20:06
Expound error when using fully-qualified symbol in let binding
(require '[clojure.core.specs.alpha])
(require '[clojure.spec.alpha :as s])
(require '[clojure.spec.test.alpha :as stest])
(require '[expound.alpha :as expound])
(set! s/*explain-out* (expound/custom-printer {:print-specs? false})) ; The "relevant specs" are very long, so let's omit them
(stest/instrument)
(let [foo/bar 42])
;; CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
@bhb
bhb / custom_printer.clj
Created February 4, 2018 01:26
Custom printer for Expound
(require '[clojure.spec.alpha :as s])
(require '[expound.alpha :as expound])
;; For a cat spec...
(s/def :ex/my-spec (s/cat
:conn any?
:x int?
:y int?))
;; with the default printer, valid values won't be printed ...
@bhb
bhb / index.html
Last active January 5, 2018 03:45
Simple template for evaluating clojurescript in browser with klipse (https://github.com/viebel/klipse)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Try klipse</title>
<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/app.klipse.tech/css/codemirror.css">
</head>
<body>
<pre class="language-klipse">
@bhb
bhb / blockchain-w-spec.md
Last active July 1, 2022 11:24
Building a blockchain, assisted by Clojure spec

Building a blockchain, assisted by Clojure spec

In an effort to gain at least a superficial understanding of the technical implementation of cryptocurrencies, I recently worked my way through "Learn Blockchains by Building One" using Clojure.

This was a good chance to experiment with using spec in new ways. At work, we primarily use spec to validate our global re-frame state and to validate data at system boundaries. For this project, I experimented with using instrumentation much more pervasively than I had done elsewhere.

This is not a guide to spec (there are already many excellent resources for this). Rather, it's an experience report exploring what went well, what is still missing, and quite a few unanswered questions for future research. If you have solutions for any of the problems I've presented, please let me know!

You don't need to know or care about blockchains to understand the code be

@bhb
bhb / expound-spec-keys.txt
Last active December 16, 2017 18:36
Expound describes missing specs
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (require '[expound.alpha :as expound])
nil
user=> (s/def ::name string?)
:user/name
user=> (s/def ::age pos-int?)
:user/age
user=> (s/def ::user (s/keys :req [::name] :req-un [::age]))
:user/user
@bhb
bhb / repl.txt
Created November 9, 2017 15:22
Testing instrumentation with expound
user=> (require '[expound.alpha :as expound])
nil
user=> (require '[clojure.spec.test.alpha :as st])
nil
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/fdef foo :args (s/cat :int int?))
user/foo
user=> (defn foo [x] x)
#'user/foo
@bhb
bhb / example.cljs
Created November 7, 2017 15:10
Two alternatives to structuring dependent side effects.
;; Problem:
;; When user clicks button, we must do async-effect-A, then async-effect-B.
;; We can't start B until A completes, because it needs the result of A.
;; We don't currently need to vary this sequence. We currently only need to
;; do [A, then B], not [A, then B] or [A, then C]
;;;;;; Implementation 1: Using a single re-frame effect
;;; in some component
@bhb
bhb / repl.txt
Created October 18, 2017 22:49
Error messages at clojure repls
;; clojure 1.8.0 - lein repl
user=> (defn hello "hello world")
IllegalArgumentException Parameter declaration missing clojure.core/assert-valid-fdecl (core.clj:7181)
;; clojure 1.9.0-beta2 - lein repl
user=> (defn hello "hello world")
@bhb
bhb / filter_spec.clj
Last active November 1, 2017 07:16
Adding your own spec for filter
(require '[clojure.spec.test.alpha :as st])
(require '[clojure.spec.alpha :as s])
(require '[expound.alpha :as expound])
(set! s/*explain-out* expound/printer)
(st/instrument)
(filter 123 "12333333333333") ; java.lang.Long cannot be cast to clojure.lang.IFn
(s/fdef clojure.core/filter
@bhb
bhb / spec_example.clj
Created September 5, 2017 14:24
Example of using `exercise` and `check` at the REPL
(require '[clojure.spec.alpha :as s])
(require '[clojure.spec.test.alpha :as st])
(require '[clojure.string :as string])
(s/def :user/name (s/and string?
#(not (empty? %))))
(s/exercise :user/name)
;; Generates list of values:
;; (["Mx" "Mx"] ["8" "8"] ["B0ZI" "B0ZI"] ["c" "c"] ["S32" "S32"] ["Rtf" "Rtf"] ["pd" "pd"] ["p5" "p5"] ["US5i9u" "US5i9u"] ["2V3kC887" "2V3kC887"])