docs/src/components/Interpreter/examples.ts
const examples = [
{
description: `With LIPS you can mix Scheme and JavaScript. You can access all JavaScript objects. You can also call any functions from Scheme.
**NOTE**: you can hover over Scheme symbols and get tooltip with documentation.`,
code: `;; &() is object literal used with quasiquote
(let ((obj \`&(:name "LIPS Scheme"
:version ,lips.version)))
;; you can access JavaScript properties
;; with dot notation, print is display + newline
(print (string-append obj.name
" "
obj.version))
;; you can mix scheme and JavaScript
(setTimeout (lambda ()
(alert (JSON.stringify obj)))
1000)
#void)`
},
{
description: 'Filter function accepts: regex or function. Curry is higher order function that creates a new function with default arguments. Pluck returns a function that extract fields from an object.',
code: `(print (filter number? '(foo 10 bar 20 baz 30)))
;; ==> (10 20 30)
(print (filter #/foo|bar/ '(foo bar baz quux)))
;; ==> (foo bar)
(define foo_or_bar (curry filter #/foo|bar/))
(print (foo_or_bar '(foo bar baz)))
;; ==> (foo bar)
;; &() is object literal used with quasiquote
(define (make-person first last)
\`&(:fist ,first :last ,last))
(define beatles (map make-person
'("John" "Paul" "Ringo" "George")
'("Lennon" "McCartney"
"Starr" "Harrison")))
;; pluck will extract properties from objects
(write (map (pluck "fist") beatles))
(newline)
;; ==> ("John" "Paul" "Ringo" "George")`
},
{
description: 'LIPS do automagic async/await. It resolve all promises by default, but you can quote a promise and handle it like in JavaScript.',
code: `;; JavaScript regular expression literal
(define re #/<h1>([^>]+)<\\/h1>/)
;; --> is a macro that allow chaining
;; of JavaScript methods calls
;; no need to use Promises because of automagic
;; promise resolving
(let ((msg (--> (fetch "https://scheme.org.pl/test/")
(text)
(match re)
1)))
(print msg))
;; explicit promise handling with quotation
(let ((promise (--> '>(fetch "https://scheme.org.pl/test/")
(then (lambda (res)
(res.text)))
(then (lambda (x)
(. (x.match re) 1))))))
(print (await promise)))`
},
{
description: 'You can use hygienic syntax-rules macro, here are also a few examples of Numeric Tower.',
code: `;; show hygienic macro prints expression
;; and the result value
(define-syntax show
(syntax-rules ()
[(_ expr ...)
(begin
(begin
(write 'expr)
(display " = ")
(write expr)
(newline))
...)]))
;; few example of Numeric Tower
(show (/ 1 2)
(expt 1/4 1/2)
(expt 10+10i 1/2)
(log 2+1/2i)
(acos -1)
(+ 1/2 1/4)
(* 3/4 1/10))`
},
{
description: 'LIPS also supports classic lisp macros. Here is example of anaphoric macro (a lambda shortcut)',
code: `(define-macro (λ . body)
\`(lambda ($1 $2 $3 $4 $5 $6 $7 $8 $8 $9) ,@body))
(print (map (λ (+ $1 1)) (range 10)))
;; ==> (1 2 3 4 5 6 7 8 9 10)
(let ((x 10))
(print (map (λ (+ $1 $2))
(range x)
(cdr (range (+ x 1))))))
;; ==> (1 3 5 7 9 11 13 15 17 19)`
},
{
description: 'Syntax extensions and custom repr allow to create new homoiconic data types.',
code: `;; Create new class using define-class macro
(define-class Person Object
(constructor (lambda (self name)
(set! self.name name))))
;; add syntax extension
(set-special! "P:" 'make-person lips.specials.SPLICE)
;; add class representation
(set-repr! Person
(lambda (x q)
(string-append "P:(" (repr x.name q) ")")))
;; function that create new object
;; for the syntax extension
(define (make-person name)
(new Person name))
;; we can use new syntax
(write P:("jon"))
(newline)
;; ==> P:("jon")
(print (. P:("jon") 'name))
;; ==> "jon"`
},
{
description: 'With LIPS you can interact with JavaScript DOM and jQuery Terminal (REPL).',
code: `;; this will query the DOM and invoke click method
(let ((selector "[class*=\\"colorModeToggle\\"] button"))
(--> (document.querySelector selector)
(click)))
;; accessing jQuery Terminal, ignore works like begin
;; but the return value is ignored so the terminal
;; is not paused when it find a Promise from
;; Terminal typing animation
(ignore
(term.css "--background" "#2E2E2E")
(term.echo "This is LIPS Scheme" &(:typing #t)))`
},
{
description: 'Dynamic variables with R7RS parameterize',
code: `;; define new dynamic parameter
(define x (make-parameter 10))
(define (double-x)
(* (x) (x)))
;; use default value
(print (double-x))
;; ==> 100
;; change the value dynamically
(parameterize ((x 20))
(print (double-x)))
;; ==> 400
`
},
{
description: 'Here is a fibonacci Closure with swap! lisp style macro.',
code: `;; macro that swap first two variables
;; with the last two expressions
(define-macro (swap! a b x y)
(let ((g_b (gensym)))
\`(let ((,g_b ,y))
(set! ,a ,b)
(set! ,b ,g_b))))
;; example taken from Go website
;; fib creates a function
;; that return fibonacci numbers
(define (fib)
(let ((a 0) (b 1))
(lambda ()
(swap! a b b (+ a b))
a)))
(let ((f (fib)))
(list (f) (f) (f) (f) (f)))`
},
{
description: 'Scheme hygienic macro that creates an assoc list, with macroexpand.',
code: `;; recursive hygienic syntax-rules macro
(define-syntax alist
(syntax-rules ()
((_) ())
((_ x y z ...)
(cons (cons x y) (alist z ...)))))
(print (alist "foo" 10 "bar" 20 "baz" 30))
;; ==> ((foo . 10) (bar . 20) (baz . 30))
(macroexpand (alist "foo" 10 "bar" 20))
;; ==> (#:cons (#:cons "foo" 10)
;; (#:cons (#:cons "bar" 20)
;; ()))`
},
{
description: 'Function that modify its source code when run',
code: `(define (repeater x)
"(repeater value)
Function prints the value 1 time and modifies itself
to repeat (+ n 1) times on the next call."
(for-each (lambda () (print x)) (range 1))
(let ((r (cadr (cdadddr (. repeater '__code__)))))
(set-cdr! r (list (+ (cadr r) 1)))))
(print "1")
(repeater 'hello)
(print "2")
(repeater 'hello)
(print "3")
(repeater 'hello)`
},
{
description: 'Built in SRFI-139 syntax-parameterize allows creating anamorphic hygienic macros.',
code: `;; define new syntax parameter
(define-syntax-parameter it
(syntax-rules ()
((_ . _)
(syntax-error "abort used outside of a loop"))))
;; syntax-rules macro aif adds (it) parameter
;; to access tested value.
(define-syntax aif
(syntax-rules ()
((_ cond rest ...)
(let ((test cond))
(syntax-parameterize
((it (syntax-rules ()
((_) test))))
(if test
rest ...))))))
;; no need to use assoc two times
;; or using a variable to hold the value
(let ((alist '((a . 10) (b . 20))))
(aif (assoc 'a alist)
(print (cdr (it)))))`
},
{
description: 'You can iterate over JavaScript generators (objects that implement iterator protocol)',
code: `;; JavaScript generator created using JS eval
(define gen (self.eval "
(async function* gen(time, ...args) {
function delay(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
for (let x of args) {
await delay(time);
yield x;
}
})"))
;; iteration over iterator/generator
(do-iterator
(i (apply gen 100 (range 10)))
()
(print i))
(print (iterator->array (gen 100 1 2 3 4 5)))
;; strings and lists are JavaScript iterators
(write (iterator->array "hello"))
(newline)
(print (iterator->array '(1 2 3 4)))`
},
{
description: 'Example of Y Combinator and inline factorial function.',
code: `(define Y
(lambda (h)
((lambda (x) (x x))
(lambda (g)
(h (lambda args (apply (g g) args)))))))
((Y (lambda (f)
(lambda (n)
(cond ((< n 0)
(throw (new Error "Invalid factorial")))
((zero? n) 1)
(else (* n (f (- n 1))))))))
10)
;; ==> 3628800`
},
{
hidden: true,
code: `(define-macro (%promisify expr)
(let ((resolve (gensym "resolve")))
\`(new Promise
(lambda (,resolve)
,(append expr (list resolve))))))
(if (null? self.$.terminal.from_ansi)
(%promisify ($.getScript "https://cdn.jsdelivr.net/npm/jquery.terminal/js/unix_formatting.js")))
(if (null? self.qrcode)
(%promisify ($.getScript "https://cdn.jsdelivr.net/gh/jcubic/static/js/qrcode.js")))
(let ((code (%promisify (qrcode.generate "https://tinyurl.com/fxv87gb"))))
(term.echo (code.replace #/\\[47m/g "[30;47m"))
#void)`
}
];
export default examples;