- A mathematician
- A coder
- A pragmatic theorist
- A freak of interactivity
- Founded Audyx in 2013 - an Audiology Startup with 30K LOCs in Clojurescript
- Author of Klipse
- A Web consultant: Full-Stack, clojure{,script}, ruby{, on rails}, javascript, react
How do regular programmers of type 0 tell stories?
They write code.
How do good programmers of type 0 tell stories?
They write code and comments.
How do excellent programmers of type 0 tell stories?
They write code, comments and tests.
How do all programmers of type 0 make their code interactive?
They encourage the reader to try it at the REPL
How do regular programmers of type 1 tell stories?
They write their ideas in a natural language.
How do good programmers of type 1 tell stories?
They write static code snippets in a programming language.
How do excellent programmers of type 1 tell stories?
They add pictures to illustrate their ideas.
How do all programmers of type 0 make their code interactive?
They include the result of the evaluation inside their static code snippets.
Problem 0: Readers are not as smart familiar with the concepts as the blog author.
They cannot digest complex code just by meditating at it.
They need to interact with it.
Problem 1: Readers are lazy.
Nobody is going to clone your github repo to interact with the code you have linked to in your blog post.
Problem Fact 2: Readers are kids.
They love to play.
Illiterate blogging with Klipse
Literate Programming: Embedding of natural language sentences in a program.
Illiterate Blogging: Embedding of interactive code snippets in a blog post.
The klipse plugin is a javascript tag that transforms static code snippets of an html page into live and interactive snippets:
The code evaluation is done in the browser: no server is involved at all!
klipse_settings
object.data-
attributes.More details in Klipse README.
Zero-delay between the trial and the result is key for creativity.
[1,2,3].map(x => x + 1)
$("#container-1")
.css({color: 'white',
backgroundColor: 'blue',
padding: '10px',
fontSize: '50px'})
.text("Hello World")
A blog post is a story.
The different elements of the stories need to be connected together.
Let’s see how to write a Hello World function in Clojure:
(defn hello [name]
(str "hello " name "\n"))
And now, let’s see how to use this function:
(hello "Klipse")
☕You can embed a jsfiddle
or a codepen
in a blog post with an <iframe>
.
But you cannot share neither the code nor the data between the iframes.
Less is more
You don’t want to confuse your readers with technical details that are not revelant to the main idea of your article.
But you need this (irrelevant) code to let the other parts of the code run properly.
Two mechanisms for hiding code from the reader but not from Klipse:
data-preamble
You can hide a snippet using CSS
<pre class="hidden"><code class="clj">
(def irrelevant-constant
42)
</code></pre>
(def irrelevant-constant 42)
There is a hidden Klipse snippet just above me
We can use the hidden code in subsequent Klipse snippets:
irrelevant-constant
We can hide part of the Klipse snippet’s code using data-preamble
.
<pre><code class="clj" data-preamble="(def random-num (rand))">
random-num
</code></pre>
random-num
Are you ready for a journey into the wonderland of programming languages?
Demonstrate EcmaScript 2017 features before they are available in the browser
const cond = true;
const obj = {
...(cond ? {a: 1} : {}),
b: 2,
};
obj
ES2017 code is transpiled by babel-standalone.
console.log
is redirected to the result box
console.log("Hello World!")
3 + 4
Let’s escape the callback hell!
async
and await
in action
async function sleep(ms = 0) {
return new Promise(r => setTimeout(r, ms));
}
async function run() {
console.log("Before: " + (new Date()).toString());
await sleep(1000);
console.log("After: " + (new Date()).toString());
}
run();
Klipse is 100% client side.
You can interact with the page that contains the Klipse snippets.
$('#container-1345')
.css({color: 'white',
backgroundColor: 'green',
padding: '10px',
fontSize: '50px'})
.text("Hello World")
1
Each Klipse snippet is bound to a container accessible through window.klipse_container
with id window.klipse_container_id
.
$(klipse_container)
.css({color: 'white',
backgroundColor: 'blue',
padding: '10px',
fontSize: '50px'})
.text("I am the container bound to the Klipse snippet just above me")
1
JSX is a language for writing react
components almost in HTML
It is transpiled into plain javascript
const element = <h1>Hello, world!</h1>;
We can mix static and dynamic pieces of code
<p style= {{color:"blue"} }>Hello, world -- 14*3={14*3}!</p>
Let’s leverage the functional power of javascript
<div>
{[1,2,3].map(i =>
<p style= {{color:"blue"} }>Hello, world -- 14*{i}={14*i}!</p>
)}
</div>
JSX code is transpiled by babel-standalone.
Learn more about JSX in this interactive JSX tutorial.
Simple stuff
[1,2]*10
Let’s have some real fun!!!
How would you call this piece of ruby code?
->(f){
f[f]
}[->(func){
->(n) { n == 0 ? 1 : n * func[func][n-1]}
}][19]
The evaluation of ruby code in the browser is powered by Opal.
Scheme
(let ((a 1)
(b 2))
(cdr (list a b a b)))
Let’s enjoy a bit of code from SICP: Recursion vs. Iteration.
Factorial implemented with recursion
(define (factorial-rec n)
(if (= n 1)
1
(* n (factorial-rec (- n 1)))))
(factorial-rec 50000)
No stack overflow because BiwaScheme is smart.
Factorial implemented with iteration (a.k.a tail-call recursion)
(define (factorial-iter n)
(fact-iter-inner 1 1 n))
(define (fact-iter-inner product counter max-count)
(if (> counter max-count)
product
(fact-iter-inner (* counter product)
(+ counter 1)
max-count)))
(factorial-iter 5)
Learn more about scheme in this Interactive overview of Scheme’s semantics.
The evaluation of scheme code in the browser is powered by BiwaScheme.
Who wants to share a fun piece of code with car
and cdr
?
A quine is a program that evaluates to its own source.
In a sense, a quine is a fixed point of Klipse.
Let’s find a unary function f
and an argument x
such that such that (f x)
is exactly (f x)
.
It’s not hard to guess that this is going to involve self-referentiality. Therefore a good guess for x
is 'f
.
(defn f [x] '(f 'f))
(f 'f)
Let’s find a way to reference f
without using f
explicitely.
(def x 'f)
x
(list 'quote x)
To get from x
to (f 'f)
, we do:
(list x (list 'quote x))
So let’s improve f
:
(defn f [x] (list x (list 'quote x)))
(f 'f)
Now if we replace f
by its definition, we get our quine:
((fn [x] (list x (list 'quote x))) '(fn [x] (list x (list 'quote x))))
Brainfuck is an esoteric language with only 8 characters.
It helps to understand what is a Turing machine
+++++++++++++++++++++++++++++++++ Increment 33 times
.
+++++++++ Increment 9 times
.
>> Move forward twice
Addition of two numbers
+++++++ put 7 on cell #0
> move to cell #1
+++ put 3 on cell # 1
< move to cell #0
[->+<] dec cell #0 and inc cell #1 until cell #0 is 0
> move to cell #1
. output cell #1
Hello World
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>
Eval
[in: ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.!]
>>>>+[->>>++>+>+++++++[<++++>>++<-]++>>+>+>+++++[>++>++++++<<-]+>>>,<++[[>[->>]<[>>]<<-]<[<]<+>>[>]>[<+>-[[<+>-]>]<[[[-]<]++<-[<+++++++++>[<->-]>>]>>]]<<]>[-]+<<[--[[-]>>-<<<+>]>>[-<<<<[>+<-]+<<+[->[<+>>>>>>+<<<<<-]<[>+<-]>>>>>>>+<[-[-[-[-[-[-[-[-[[-]>-<]>[-<<+++++++>>]<]]]>[-]<]>[-<<+++>>]<]>[-<<+>>]<]>[-]<]>[-<<<<<<<+>>>>>>>]<]>[-]<<<<<]>>>[<<+>>-]<+<[-[-[-[-[-[-[-[-[-[-[[-]>-<<<[-]<<+>>]]]]>[-]<]>[-<<<[-]<<+++++++>>>]<]]]>[-]<]>[-<<<[-]<<+++++++>>>]<]]>[-]<<<<<<[-]>>[-<<<[>+>>+<<<-]>[<+>-]>>[-[-[[-]>>]>[<<[<+>>+<-]>[<+>-]+<<-[-[-[-[-[-[-[-[-[-[-<+>]<+++++++++++++>>[-]>->-<<]]]>>[->>>>>]<<]>>[-<<<++++++++++++>>[-]>>-]<<]>>[->>>>>]<<]>>[-<<<+++++++++++>>[-]>>-]<<]>>[-<<<++++++++++>>[-]>>-]<<]]>>[->>>>>]<<]<]]>[>>]<<<]>>+>>>]<<]>>[->+>]<<<]<<[<<]>>[[<+>>+<-]+<-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[->->>[>>]>>[>>]<[<-<<-<]<[<<]<<[<<]<]>[->>[>>]>>[>>]<[>+>>+>]<[<<]<<[<<]]<]>[->>[>>]>>[>>]<[-]<[<<]<<[<<]]<]>[->>[>>]>>[>>]<[<-<]<[<<]<<[<<]]<]>[->>[>>]>>[>>]<[>+>]<[<<]<<[<<]]<]>[->>[>>]>>[>>]<<-<<-<<[<<]<<[<<]]<]>[->>[>>]>>[>>]+>>+[<<]<<[<<]]<]>[->>[>>]>>[>>]<++<[<<]<<[<<]]<]>[->>[>>]>>[>>]<+<[<<]<<[<<]]<]>[->>[>>]>>[>>]<,<[<<]<<[<<]]<]>[->>[>>]>>[>>]<-<[<<]<<[<<]]<]>[->>[>>]>>[>>]<.<[<<]<<[<<]]<]>[->>[>>]>>[>>]<<-<<[<<]<<[<<]]<]>[->>[>>]>>[>>]+[<<]<<[<<]]<]>[->>[>>]>>[>>]<[>+>>+<<<-]>[<+>-]>>[<<+>>[-]]+<<[>>-<<-]>>[<<+>>>>+<<-]>>[<<+>>-]<<[>>+<<-]+>>[<<->>-]<<<<[-<<[<<]<<[<<]<<<<<++>>]>>[-<<<<<<[<<]<<[<<]<]>]<]>[->>[>>]>>[>>]<[>+>>+<<<-]>[[<+>-]>>[-]+<<]>>[<<+>>>>+<<-]>>[<<+>>-]<<[>>+<<-]+>>[<<->>-]<<<<[-<<[<<]<<[<<]<<<<<+>>]>>[-<<<<<<[<<]<<[<<]<]>]>[<+>-]<<<<<<[>>+<<-[->>->>+[>>>[-<+>>+<]+<-[-[[-]>-<]>[-<<<+>>>]<]>[-<<<->>>]>[-<+>]<<<<[>>+<<-]>>]<<<<<<]>>[-<<+[>>>[-<+>>+<]+<-[-[[-]>-<]>[-<<<->>>]<]>[-<<<+>>>]>[-<+>]<<<<[<<+>>-]<<]]]>>>>>>>]
function hello(s)
print("Hello " .. s)
end
print("Hello " .. "World!")
The evaluation of lua code in the browser is powered by wasm_lua.
Python
print([x + 1 for x in range(10)])
Python Turtle
import turtle
t = turtle.Turtle()
for i in range(4):
t.forward(150)
t.left(90)
You can even draw fractals with the python turtle.
The evaluation of python code in the browser is powered by Skulpt.
All the details are in Klipse README
Let’s write our first illiterate blog post together
powered by Klipse /