diff --git a/404.html b/404.html index 022825fb..3e195fbe 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ Page Not Found | LIPS Scheme - + diff --git a/assets/js/e1902777.57d1fa3f.js b/assets/js/e1902777.57d1fa3f.js deleted file mode 100644 index 48c1ce9e..00000000 --- a/assets/js/e1902777.57d1fa3f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[5609],{5264:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>l});var r=s(5893),a=s(1151);const i={sidebar_position:1,description:"Core LIPS features added on top of Scheme, related to JavaScript"},c="Core features",t={id:"lips/intro",title:"Core features",description:"Core LIPS features added on top of Scheme, related to JavaScript",source:"@site/docs/lips/intro.md",sourceDirName:"lips",slug:"/lips/intro",permalink:"/docs/lips/intro",draft:!1,unlisted:!1,editUrl:"https://github.com/jcubic/lips/tree/master/docs/docs/lips/intro.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,description:"Core LIPS features added on top of Scheme, related to JavaScript"},sidebar:"tutorialSidebar",previous:{title:"LIPS introduction",permalink:"/docs/category/lips-introduction"},next:{title:"Reflection",permalink:"/docs/lips/reflection"}},o={},l=[{value:"Special constants",id:"special-constants",level:2},{value:"Numerical tower",id:"numerical-tower",level:2},{value:"Print procedure",id:"print-procedure",level:2},{value:"Emoji",id:"emoji",level:2},{value:"Macros",id:"macros",level:2},{value:"Gensyms",id:"gensyms",level:3},{value:"Single argument eval",id:"single-argument-eval",level:2},{value:"Procedures",id:"procedures",level:2},{value:"length property",id:"length-property",level:3},{value:"Doc strings",id:"doc-strings",level:2},{value:"Typechecking",id:"typechecking",level:2},{value:"Integration with JavaScript",id:"integration-with-javascript",level:2},{value:"Dot notation",id:"dot-notation",level:3},{value:"Mutating object properties",id:"mutating-object-properties",level:3},{value:"Boxing",id:"boxing",level:3},{value:"Procedures",id:"procedures-1",level:3},{value:"Procedure arity",id:"procedure-arity",level:4},{value:"Helper macros and functions",id:"helper-macros-and-functions",level:3},{value:"Legacy macros and functions",id:"legacy-macros-and-functions",level:4},{value:"Scheme functions",id:"scheme-functions",level:3},{value:"JavaScript functions",id:"javascript-functions",level:3},{value:"Callbacks",id:"callbacks",level:3},{value:"Regular Expressions",id:"regular-expressions",level:3},{value:"Vectors",id:"vectors",level:3},{value:"Object literals",id:"object-literals",level:3},{value:"Automagic async/await",id:"automagic-asyncawait",level:3},{value:"Promise quotation",id:"promise-quotation",level:3},{value:"Promises vs delay expression",id:"promises-vs-delay-expression",level:3},{value:"Exceptions",id:"exceptions",level:3},{value:"JavaScript Generars and iterators",id:"javascript-generars-and-iterators",level:3},{value:"Classes",id:"classes",level:3},{value:"Node.js",id:"nodejs",level:3},{value:"Binary compiler",id:"binary-compiler",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"core-features",children:"Core features"}),"\n",(0,r.jsx)(n.h2,{id:"special-constants",children:"Special constants"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define ",(0,r.jsx)(n.code,{children:"#null"})," and ",(0,r.jsx)(n.code,{children:"#void"})," as Parser constants so they can be used inside quoted expressions:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((lst '(#null #void)))\n (write (symbol? (car lst)))\n (newline)\n (write (symbol? (cadr lst)))\n (newline))\n;; ==> #f\n;; ==> #f\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," ",(0,r.jsx)(n.code,{children:"#null"})," is the same as JavaScript ",(0,r.jsx)(n.code,{children:"null"})," value and it's a false value. Similar to\n",(0,r.jsx)(n.a,{href:"https://www.gnu.org/software/kawa/index.html",children:"Kawa Scheme"})," that use ",(0,r.jsx)(n.code,{children:"#!null"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"#void"})," constants is the same as result of ",(0,r.jsx)(n.code,{children:"(value)"})," or ",(0,r.jsx)(n.code,{children:"(if #f #f)"}),". In Scheme it's unspecified value,\nbut in LIPS it's JavaScript undefined. ",(0,r.jsx)(n.code,{children:"#void"})," is not false value."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(eq? (if #f #f) (values))\n;; ==> #t\n"})}),"\n",(0,r.jsx)(n.h2,{id:"numerical-tower",children:"Numerical tower"}),"\n",(0,r.jsx)(n.p,{children:"LIPS support full numerical tower (not yet 100% unit tested):"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"integers - using BitInt"}),"\n",(0,r.jsx)(n.li,{children:"floats - using JavaScript numbers"}),"\n",(0,r.jsx)(n.li,{children:"rationals"}),"\n",(0,r.jsx)(n.li,{children:"complex numbers (that can use integers, floats, or rationals)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"print-procedure",children:"Print procedure"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define helper ",(0,r.jsx)(n.code,{children:"print"})," procedure that display all its arguments with newline after each element."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(print 1 2 3)\n;; ==> 1\n;; ==> 2\n;; ==> 3\n"})}),"\n",(0,r.jsx)(n.h2,{id:"emoji",children:"Emoji"}),"\n",(0,r.jsx)(n.p,{children:"LIPS fully supports all Unicode characters, including emoji:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define smiley #\\\ud83d\ude00)\n(define poo #\\\ud83d\udca9)\n(write (string-append (string smiley) " " (string poo)))\n;; ==> "\ud83d\ude00 \ud83d\udca9"\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can also use them as part of symbols (e.g. as variables name):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define (\u23cf\ufe0f)\n (print "ejecting"))\n(\u23cf\ufe0f)\n;; ==> ejecting\n'})}),"\n",(0,r.jsx)(n.h2,{id:"macros",children:"Macros"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define both Lisp macros and Scheme hygienic macros (",(0,r.jsx)(n.code,{children:"syntax-rules"}),")."]}),"\n",(0,r.jsx)(n.p,{children:"It also implements:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/",children:"SRFI-46"})," which allows changing the ellipsis symbol for nested syntax-rules."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/",children:"SRFI-139"})," which allows defining\n",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/macros#anaphoric-hygienic-macros",children:"anaphoric syntax-rules macros"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-147/",children:"SRFI-147"})," which allows defining a new syntax-rules macros to define syntax-rules macros."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"gensyms",children:"Gensyms"}),"\n",(0,r.jsxs)(n.p,{children:["With lisp macros you can use ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/macros#gensyms",children:"gensyms"}),", they are special Scheme\nsymbols that use JavaScript symbols behind the scene, so they are proven to be unique. Additionally\nyou can use named gensym if you pass string as first argument:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(gensym)\n;; ==> #:g5\n(gensym "sym")\n;; ==> #:sym\n'})}),"\n",(0,r.jsx)(n.h2,{id:"single-argument-eval",children:"Single argument eval"}),"\n",(0,r.jsxs)(n.p,{children:["Eval in LIPS don't require second argument to ",(0,r.jsx)(n.code,{children:"eval"}),". The environment is optional and default\nit's a result of calling ",(0,r.jsx)(n.code,{children:"(interaction-environment)"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(eval '(+ x x))\n;; ==> 20\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(let ((x 20))\n (eval '(- x)))\n;; ==> -10\n"})}),"\n",(0,r.jsx)(n.p,{children:"But you can also use the second arguments:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(let ((x 20))\n (eval '(- x) (current-environment)))\n;; ==> -20\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Read more about ",(0,r.jsx)(n.a,{href:"/docs/lips/environments",children:"LIPS environments"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"procedures",children:"Procedures"}),"\n",(0,r.jsxs)(n.p,{children:["Procedures in LIPS have access additional objects ",(0,r.jsx)(n.code,{children:"arguments"}),", but the have nothing to do with JavaScript.\narguments is an array/vector with calling arguments and it have an object callee which points to the same\nprocedure. So you can create recursive functions with anonymous lambda:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"((lambda (n)\n (if (<= n 0)\n 1\n (* n (arguments.callee (- n 1))))) 10)\n;; ==> 3628800\n"})}),"\n",(0,r.jsx)(n.p,{children:"This is classic factorial function written as lambda without the name."}),"\n",(0,r.jsx)(n.h3,{id:"length-property",children:"length property"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS functions similarly to JavaScript functions also have ",(0,r.jsx)(n.code,{children:"length"})," property that indicate how many\narguments a function accepts. If function get more or less argumenets it's not an error like in Scheme. More arguments are ignored,\nand if less arguments are passed they are ",(0,r.jsx)(n.code,{children:"undefined"})," (",(0,r.jsx)(n.code,{children:"#void"}),")."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define (sum a b c)\n (+ a b c))\n\n(print sum.length)\n;; ==> 3\n"})}),"\n",(0,r.jsx)(n.p,{children:"It return number of number arguments the rest (dot notation) arguments are ignored."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define (sum a b . rest)\n (apply + a b rest))\n\n(print sum.length)\n;; ==> 3\n(sum 1 2 3 4 5 6)\n;; ==> 21\n"})}),"\n",(0,r.jsx)(n.h2,{id:"doc-strings",children:"Doc strings"}),"\n",(0,r.jsx)(n.p,{children:"Procedures, macros, and variables can have doc strings."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define (factorial n)\n "(factorial n)\n\n Calculate factorial of a given number"\n (if (<= n 0)\n 1\n (* n (factorial (- n 1)))))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can access doc string with ",(0,r.jsx)(n.code,{children:"help"})," procedure or with ",(0,r.jsx)(n.code,{children:"__doc__"})," property."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(write factorial.__doc__)\n"(factorial n)\n\nCalculate factorial of a given number"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["If you define variable or hygienic macro with doc string, the string is hidden (you can access it with ",(0,r.jsx)(n.code,{children:"__doc__"}),"),\nso help is the only way to access it:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define-syntax q\n (syntax-rules ()\n ((_ x) \'x))\n "(q expression)\n\n Macro quote the expression")\n\n(write q.__doc__)\n;; ==> #void\n(help q)\n;; ==> (q expression)\n;; ==>\n;; ==> Macro quote the expression\n'})}),"\n",(0,r.jsx)(n.h2,{id:"typechecking",children:"Typechecking"}),"\n",(0,r.jsx)(n.p,{children:"LIPS do typechecking for all scheme procedures."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(+ "hello" 10)\n;; ==> Expecting number got string\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can incorporate typechecking in your own code:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((x 10))\n (typecheck "let" x "string" 0))\n;; ==> Expecting string got number in expression `let` (argument 0)\n(let ((x "string"))\n (typecheck "let" x "number"))\n;; ==> Expecting number got string in expression `let`\n'})}),"\n",(0,r.jsx)(n.p,{children:"There is also another function to check type of number:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((i 10+10i))\n (typecheck-number "let" i "bigint"))\n;; ==> Expecting bigint got complex in expression `let`\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": In LIPS all integers are BigInts."]}),"\n",(0,r.jsxs)(n.p,{children:["The last typecking function is ",(0,r.jsx)(n.code,{children:"typecheck-args"})," that check if all arguments are of same type."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((number \'(1 10 1/2 10+10i)))\n (typecheck-args "number" "let" number))\n;; ==> #void\n(let ((number \'(1 10 1/2 "string")))\n (typecheck-args "number" "let" number))\n;; ==> Expecting number got string in expression `let` (argument 4)\n'})}),"\n",(0,r.jsx)(n.h2,{id:"integration-with-javascript",children:"Integration with JavaScript"}),"\n",(0,r.jsx)(n.h3,{id:"dot-notation",children:"Dot notation"}),"\n",(0,r.jsx)(n.p,{children:"LIPS allow accessing JavaScript objects with dot notation:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"document.querySelector\n;; ==> #\n"})}),"\n",(0,r.jsx)(n.h3,{id:"mutating-object-properties",children:"Mutating object properties"}),"\n",(0,r.jsxs)(n.p,{children:["You can use dot notation with ",(0,r.jsx)(n.code,{children:"set!"})," to change the value:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(set! self.foo 10)\nself.foo\n"})}),"\n",(0,r.jsxs)(n.p,{children:["top level ",(0,r.jsx)(n.code,{children:"self"})," always points to a global object ",(0,r.jsx)(n.code,{children:"window"})," in browser or ",(0,r.jsx)(n.code,{children:"global"})," in Node."]}),"\n",(0,r.jsxs)(n.p,{children:["There is also older API that still work, which is ",(0,r.jsx)(n.code,{children:"set-obj!"})," but with dot notation you don't\nneed it anymore:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(set-obj! self 'foo 10)\n(display self.foo)\n;; ==> 10\n"})}),"\n",(0,r.jsx)(n.p,{children:"In both platforms you can access global JavaScript objects like normal variables:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! self.greet "hello, LIPS")\n(write greet)\n;; ==> "hello, LIPS"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"boxing",children:"Boxing"}),"\n",(0,r.jsx)(n.p,{children:"LIPS have its own representation for numbers, strings and characters. And when\ninteracting with JavaScript the values may get boxed or unboxed automagically."}),"\n",(0,r.jsxs)(n.p,{children:["You should not confuse boxing with boxes (",(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-111/",children:"SRFI-111"})," and\n",(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-195",children:"SRFI-195"}),"). LIPS boxes are part of implementation of Scheme\ndata types. And SRFI boxes are containers written in Scheme. Name boxing came from JavaScript, when\nprimitive values are wrapped in objects when you try to use them in object context (like accessing\na property)."]}),"\n",(0,r.jsx)(n.p,{children:"You need to be careful with some of the JavaScript native methods, since they can unbox the value when you don't\nwhen them to be unboxed."}),"\n",(0,r.jsxs)(n.p,{children:["Example is ",(0,r.jsx)(n.code,{children:"Array::push"})," using with native LIPS types:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((v (vector)))\n (v.push 1/2)\n (print v))\n;; ==> #(0.5)\n"})}),"\n",(0,r.jsx)(n.p,{children:"As you can see the rational number got unboxed and converted into JavaScript float numbers.\nUnboxing always can make you loose some information because LIPS types needs to be converted into native JavaScript\ndata types. And JavaScript doesn't have a notion of rationals, there are only floating point numbers, and big ints."}),"\n",(0,r.jsx)(n.h3,{id:"procedures-1",children:"Procedures"}),"\n",(0,r.jsx)(n.p,{children:"LIPS Scheme procedures are JavaScript functions, so you can call them from JavaScript."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! self.greet (lambda () "hello, LIPS"))\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can call this function from JavaScript"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:"console.log(greet());\n// ==> {__string__: 'hello, LIPS'}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note that the value was not automagically unboxed because we are no longer in LIPS Scheme code and LIPS can't access native\nJavaScript. So to get the real a string you need to call ",(0,r.jsx)(n.code,{children:"valueoOf()"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:"console.log(greet().valueOf());\n// ==> hello, LIPS\n"})}),"\n",(0,r.jsx)(n.h4,{id:"procedure-arity",children:"Procedure arity"}),"\n",(0,r.jsx)(n.p,{children:"LIPS don't check the number of argumnents when calling a procedure:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((test (lambda (a b c)\n (print a b c))))\n (test 10))\n;; ==> 10\n;; ==> #void\n;; ==> #void\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The same as with JavaScript if you don't pass an argument it will be undefined. But you still have full compatible with Scheme and use ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/core#variable-number-of-arguments",children:"arguments with variable artity"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((test (lambda (first . rest)\n (apply print first rest))))\n (test 1)\n (test 2 3 4))\n;; ==> 1\n;; ==> 2\n;; ==> 3\n;; ==> 4\n"})}),"\n",(0,r.jsx)(n.h3,{id:"helper-macros-and-functions",children:"Helper macros and functions"}),"\n",(0,r.jsxs)(n.p,{children:["The most useful macro in LIPS (for interacting with JavaScript) is ",(0,r.jsx)(n.code,{children:"--\x3e"})," it acts like a chain of\nmethod calls in JavaScript"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e "this is string" (split " ") (reverse) (join " "))\n;; ==> "string is this"\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can chain methods that return arrays or string and call a method of them. The above expression\nis the same as JavaScript:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:"\"this is string\".split(' ').reverse().join(' ');\n"})}),"\n",(0,r.jsx)(n.p,{children:"With --\x3e you can also gab property of a function:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #/x/ (test.call #/foo/ "foo"))\n;; ==> #t\n(let ((test-bar (--\x3e #/x/ (test.bind #/bar/i))))\n (test-bar "BAR"))\n;; ==> #t\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can also return a function:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define test (--\x3e #/x/ test))\n(test.call #/foo/ "foo")\n;; ==> #t\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Read more about ",(0,r.jsx)(n.a,{href:"https://tinyurl.com/ykvb836s",children:"function::bind"})," and\n",(0,r.jsx)(n.a,{href:"https://tinyurl.com/yc6j7fdh",children:"function::call"})," on ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/",children:"MDN"}),"."]}),"\n",(0,r.jsx)(n.h4,{id:"legacy-macros-and-functions",children:"Legacy macros and functions"}),"\n",(0,r.jsx)(n.p,{children:"There are two legacy macros that are still part of LIPS, but you don't need\nthem most of the time."}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"."})," - dot function was a first way to interact with JavaScript, it allowed to\nget property from an object:"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(. document 'querySelector)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This returned function querySelector from document object in browser. Note that dot a function can only appear\nas first element of the list (it's handled in special way by the parser). In any other place dot is a pair separator,\nsee documentation about ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/data-types#pairs",children:"Pairs in Scheme"}),"."]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".."})," - this is a macro is that simplify usage of ",(0,r.jsx)(n.code,{children:"."})," procedure:"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(.. document.querySelector)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["You still sometimes may want to use this instead of ",(0,r.jsx)(n.code,{children:"--\x3e"})," when you want to get\nproperty from an object returned by expression."]}),"\n",(0,r.jsx)(n.p,{children:"In the old version of LIPS, you have to execute code like this:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'((. document \'querySelector) "body")\n((.. document.querySelector) "body")\n'})}),"\n",(0,r.jsx)(n.p,{children:"The first expression return a Native JavaScript procedure that is then executed."}),"\n",(0,r.jsx)(n.p,{children:"This is equivalent of:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(document.querySelector "body")\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," the only time when you still need ",(0,r.jsx)(n.code,{children:"."})," function is when you want to get the property of\nobject returned by expression."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((style (. (document.querySelector "body") \'style)))\n (set! style.background "red"))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Here we get a ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style",children:"style object"}),"\nfrom ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement",children:"the DOM node"})," without sorting the\nreference to the DOM node."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," because dot notation in symbols is not special syntax you can use code like this:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((x #(1 2 3)))\n (print x.0)\n (print x.1)\n (print x.2))\n;; ==> 1\n;; ==> 2\n;; ==> 3\n"})}),"\n",(0,r.jsx)(n.h3,{id:"scheme-functions",children:"Scheme functions"}),"\n",(0,r.jsx)(n.p,{children:"Scheme functions (lambda's) are JavaScript functions, so you can call them from JavaScript."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! window.foo (lambda () (alert "hello")))\n'})}),"\n",(0,r.jsx)(n.p,{children:"If you define function like this, in browser REPL, you can call it from JavaScript\n(e.g. browser developer console)."}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"TODO"})," Screenshot"]}),"\n",(0,r.jsx)(n.h3,{id:"javascript-functions",children:"JavaScript functions"}),"\n",(0,r.jsx)(n.p,{children:"You can call JavaScript functions from Scheme, the same as you call Scheme procedures:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(document.querySelector "body")\n;; ==> #\n'})}),"\n",(0,r.jsxs)(n.p,{children:["In both browser and Node.js you can execute ",(0,r.jsx)(n.code,{children:"console.log"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(console.log "hello, LIPS")\n;; ==> hello, LIPS\n'})}),"\n",(0,r.jsx)(n.h3,{id:"callbacks",children:"Callbacks"}),"\n",(0,r.jsx)(n.p,{children:"You can use Scheme functions as callbacks to JavaScript functions:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("1" "2" "3") (map string->number))\n;; ==> #(1 +nan.0 +nan.0)\n'})}),"\n",(0,r.jsx)(n.p,{children:"This is classic issue with functions that accept more than one argument. You have samilar issue\nin JavaScript:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:'["1", "2", "3"].map(parseInt)\n// ==> [1, NaN, NaN]\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": the value are different becaseu in Shceme i"]}),"\n",(0,r.jsx)(n.p,{children:"To fix the issue you can\ndefine lambda with single argument:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("1" "2" "3") (map (lambda (str) (string->number str))))\n;; ==> #(1 2 3)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can also use one of functional helpers insprired by ",(0,r.jsx)(n.a,{href:"https://ramdajs.com/",children:"Ramda"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("1" "2" "3") (map (unary string->number)))\n;; ==> #(1 2 3)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"unary"})," ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/core#higher-order-functions",children:"higher-order procedure"})," accept a single\nprocedure and return new procedure that accept only one argument."]}),"\n",(0,r.jsxs)(n.p,{children:["To read more check ",(0,r.jsx)(n.a,{href:"/docs/lips/functional-helpers",children:"Functional helpers"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"WARNING"})," be careful when using scheme callback functions inside JavaScript.\nSince some code may be ",(0,r.jsx)(n.code,{children:"async"})," and your code may break."]}),"\n",(0,r.jsx)(n.p,{children:"Example of procedures that are not wise to use are:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Array::forEach"})," - this function accepts a callaback but because it doesn't return\nanything, LIPS can't automatically await the response, and your code may execute out of order."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"String::replace"})," - this function can accept optional callback and if ",(0,r.jsx)(n.code,{children:"lambda"})," is async\nyou will end up with ",(0,r.jsx)(n.code,{children:"[object Promise]"})," in output string. Any macro or function can return\na promise in LIPS, and if any of the expression inside a function return a Promise, the whole\nfunction return a Promise and become async. Here is example code that demonstrate the problem:"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e "foo bar" (replace "foo" (lambda () (Promise.resolve "xxx"))))\n"[object Promise] bar"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Instead of ",(0,r.jsx)(n.code,{children:"Array::replace"})," you should use LIPS Scheme ",(0,r.jsx)(n.code,{children:"replace"})," procedure that works with async ",(0,r.jsx)(n.code,{children:"lambda"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(replace #/[a-z]+/g (lambda ()\n (Promise.resolve "lips"))\n "foo bar")\n;; ==> "lips lips"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"regular-expressions",children:"Regular Expressions"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define regular expressions it uses native JavaScript regular expressions.\nAt first, the syntax looked like in JavaScript. It was problematic for the parser\nso you were not able to put space after ",(0,r.jsx)(n.code,{children:"/"})," to distinguish from divide procedure.\nLater, the syntax was renamed into form that start with hash ",(0,r.jsx)(n.code,{children:"#/[0-9]/"}),". The same\nsyntax is used by ",(0,r.jsx)(n.a,{href:"https://practical-scheme.net/gauche/man/gauche-refe/Regular-expressions.html",children:"Gauche"})," implementation. But LIPS supports more flags (same as JavaScript)."]}),"\n",(0,r.jsx)(n.h3,{id:"vectors",children:"Vectors"}),"\n",(0,r.jsxs)(n.p,{children:["In LIPS Scheme vectors are JavaScript arrays. So you can execute methods on them with ",(0,r.jsx)(n.code,{children:"--\x3e"})," macro:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("one" "two" "three") (join ":"))\n;; ==> "one:two:three"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"object-literals",children:"Object literals"}),"\n",(0,r.jsxs)(n.p,{children:["In LIPS you can define object literals with ",(0,r.jsx)(n.code,{children:"&"}),"\n",(0,r.jsx)(n.a,{href:"/docs/lips/extension#syntax-extensions",children:"syntax extension"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define obj &(:name "Jack" :age 22))\n(write obj)\n;; ==> &(:name "Jack" :age 22)\n(console.log obj)\n;; ==> { name: \'Jack\', age: 22 }\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can nest object literals and mix them with different object:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define obj &(:name "Jack" :hobbies #("swimming" "programming")))\n(write obj.hobbies)\n;; ==> #("swimming" "programming")\n(console.log obj)\n;; ==> { name: \'Jack\', hobbies: [ \'swiming\', \'programming\' ] }\n'})}),"\n",(0,r.jsx)(n.p,{children:"Object similar to Scheme vectors, are immutable, and everything inside is quoted automatically:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define obj &(:name Jack))\n(write obj)\n;; ==> &(:name "Jack")\n'})}),"\n",(0,r.jsx)(n.p,{children:"But to make it possible to share objects with JavaScript, native LIPS values are automatically unboxed.\nSo instead of symbol representation you get a JavaScript string."}),"\n",(0,r.jsx)(n.p,{children:"You can also use quasiquote with object literals:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define jack (let ((name "Jack")\n (age 22))\n `&(:name ,name :age ,age)))\n(write jack)\n;; ==> &(:name "Jack" :age 22)\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": because of the construction of ",(0,r.jsx)(n.a,{href:"/docs/lips/extension#syntax-extensions",children:"syntax extensions"})," and\n",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/data-types#quasiquote",children:"quasiquote"}),", you can't splice a list inside object literals:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((args (list \':foo "lorem" \':bar "ipsum")))\n `&(,@args))\n;; ==> pair (unquote-splicing args) is not a symbol!\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The reason why this work like this is because, syntax extensions (",(0,r.jsx)(n.code,{children:"&"}),") runs at parse time and LIPS macros are runtime.\nThis may change in the future when ",(0,r.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/169",children:"expansion time will be implemented"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["Objects also have longhand form with ",(0,r.jsx)(n.code,{children:"object"})," macro:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((obj (object :name \'Jack)))\n (write obj))\n;; ==> &(:name "Jack")\n'})}),"\n",(0,r.jsx)(n.p,{children:"But note that object macro is async (return a Promise) so it may be problematic when used it\nwith native JavaScript code."}),"\n",(0,r.jsxs)(n.p,{children:["Using long form ",(0,r.jsx)(n.code,{children:"(object)"})," syntax you can use splicing with help of ",(0,r.jsx)(n.code,{children:"eval"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((args \'(:foo "lorem" :bar "ipsum")))\n (eval `(object ,@args)))\n;; ==> &(:foo "lorem" :bar "ipsum")\n'})}),"\n",(0,r.jsx)(n.p,{children:"The same you can use macros that will return LIPS Scheme code:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define-macro (create-object . args)\n `(object ,@args))\n\n(create-object :foo "lorem" :bar "ipsum")\n;; ==> &(:foo "lorem" :bar "ipsum")\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": this example macro works the same ",(0,r.jsx)(n.code,{children:"object"})," is it's not that useful, but you can create\nmore complex code where you will be able to generate object literals with splicing."]}),"\n",(0,r.jsx)(n.p,{children:"Object literal also have shorthad notation:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((obj &(:x :y)))\n (write obj))\n;; ==> &(:x #void :y #void)\n"})}),"\n",(0,r.jsx)(n.p,{children:"It creates two writtable slots, the rest of the props are read only:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((obj &(:x :y)))\n (set! obj.x 10)\n (set! obj.y 20)\n (write obj))\n;; ==> &(:x 10 :y 20)\n\n(let ((obj &(:x :y)))\n (set! obj.z 20)\n (write obj))\n;; ==> Cannot add property z, object is not extensible\n\n(let ((obj &(:x :y :z 10)))\n (set! obj.z 20)\n (write obj))\n;; ==> Cannot assign to read only property 'z' of object '#'\n"})}),"\n",(0,r.jsx)(n.h3,{id:"automagic-asyncawait",children:"Automagic async/await"}),"\n",(0,r.jsx)(n.p,{children:"LIPS do automatic async/await so it waits for any promise before evaluating\nnext expression."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(Promise.resolve "xxx")\n;; ==> "xxx"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["This simplifies code when using promises, for instance using\n",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API",children:"fetch API"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e (fetch "https://scheme.org.pl/test/") (text) (match #/

([^>]+)<\\/h1>/) 1)\n;; ==> "Scheme is Super Fun"\n'})}),"\n",(0,r.jsx)(n.p,{children:"This is equivalent of JavaScript using async/await:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:'cons res = await fetch("https://scheme.org.pl/test/");\nconst text = await res.text();\ntext.match(/

([^>]+)<\\/h1>/)[1];\n'})}),"\n",(0,r.jsx)(n.h3,{id:"promise-quotation",children:"Promise quotation"}),"\n",(0,r.jsxs)(n.p,{children:["Sometimes you need to process promises as values, for this LIPS support quotation\nof promises. You escape automagic async/await realm and get access to promise as value:\nto quote a promise you use ",(0,r.jsx)(n.code,{children:"'>"}),"\n",(0,r.jsx)(n.a,{href:"/docs/lips/extension#syntax-extensions",children:"syntax extension"}),". To again get into\nautomatic async/await you can use ",(0,r.jsx)(n.code,{children:"(await)"})," procedure"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((promise (--\x3e \'>(fetch "https://scheme.org.pl/test/")\n (then (lambda (res)\n (res.text)))\n (then (lambda (text)\n (. (text.match #/

([^>]+)<\\/h1>/) 1))))))\n (print (await promise)))\n;; ==> Scheme is Super Fun\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," Inside ",(0,r.jsx)(n.code,{children:"then"})," lambda promises are still automagically resolved."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e \'>(Promise.resolve "hello")\n (then (lambda (value)\n (print (string-append value " " (Promise.resolve "LIPS"))))))\n;; ==> hello LIPS\n'})}),"\n",(0,r.jsx)(n.h3,{id:"promises-vs-delay-expression",children:"Promises vs delay expression"}),"\n",(0,r.jsxs)(n.p,{children:["Don't confuse JavaScript promises with ",(0,r.jsx)(n.code,{children:"delay"})," expressions. Their representation looks similar:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(delay 10)\n;; ==> #\n'>(Promise.resolve 10)\n;; ==> #\n"})}),"\n",(0,r.jsxs)(n.p,{children:["You can check if a value is a promise by quoting the expression and using ",(0,r.jsx)(n.code,{children:"promise?"})," predicate:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((a '>10)\n (b '>(Promise.resolve 10)))\n (print (promise? a))\n (print (promise? b)))\n;; ==> #f\n;; ==> #t\n"})}),"\n",(0,r.jsx)(n.h3,{id:"exceptions",children:"Exceptions"}),"\n",(0,r.jsx)(n.p,{children:"LIPS Scheme use javascript exception system. To throw an exception you use:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(throw "This is error")\n;; ==> Error: This is error\n'})}),"\n",(0,r.jsx)(n.p,{children:"or"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(raise (new Error "error"))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"raise"})," procedure throw any object and ",(0,r.jsx)(n.code,{children:"throw"})," wraps the argument in ",(0,r.jsx)(n.code,{children:"new Error"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"You can catch exceptions with LIPS specific try..catch..finally:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(try\n (throw "nasty")\n (catch (e)\n (print (string-append "error " e.message " was caught"))))\n;; ==> error nasty was caught\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can also have finally expression:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(try\n (throw "nasty")\n (catch (e)\n (print (string-append "error " e.message " was caught")))\n (finally\n (print "nothing happened")))\n;; ==> error nasty was caught\n;; ==> nothing happened\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can also define ",(0,r.jsx)(n.code,{children:"finally"})," without ",(0,r.jsx)(n.code,{children:"catch"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(try\n (throw "nasty")\n (finally\n (print "after error")))\n;; ==> after error\n;; ==> nasty\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," the order of execution is not expected, but it may change in the future."]}),"\n",(0,r.jsxs)(n.p,{children:["LIPS also define R",(0,r.jsx)("sup",{children:"7"}),"RS guard ",(0,r.jsx)(n.code,{children:"procedure"})," that is just a macro that use try..catch behind the scene:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(guard (e ((list? e) (print (string-append "Error: " (car e)))))\n (raise \'("error")))\n;; ==> Error: error\n'})}),"\n",(0,r.jsx)(n.h3,{id:"javascript-generars-and-iterators",children:"JavaScript Generars and iterators"}),"\n",(0,r.jsxs)(n.p,{children:["Right now there is no way to define JavaScript generators inside LIPS. You can create iterator using\n",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols",children:"iteration prorocol"}),",\nBut to have yield keyword you need ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/continuations",children:"continuations"}),", they are part of the\nLIPS Roadmap."]}),"\n",(0,r.jsx)(n.p,{children:"Here is example of creating iterator in LIPS:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((obj (object))\n (max 5))\n (set-obj! obj Symbol.iterator\n (lambda ()\n (let ((i 0))\n `&(:next ,(lambda ()\n (set! i (+ i 1))\n (if (> i max)\n `&(:done #t)\n `&(:done #f :value ,(/ 1 i))))))))\n (print (iterator->array obj))\n (print (Array.from obj)))\n;; ==> #(1 1/2 1/3 1/4 1/5)\n;; ==> #(1 1/2 1/3 1/4 1/5)\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"Array.from"})," can't be used for every possible case because it will unbox the values (and convert\nrational to float), here it doesn't happen because LIPS don't treat JavaScript iterators in any\nspecial way (it may change in the future). But ",(0,r.jsx)(n.code,{children:"Array.from"})," will convert the array of rationals to\nfloat if used on normal vector:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(Array.from #(1/2 1/3 1/4 1/5))\n;; ==> #(0.5 0.3333333333333333 0.25 0.2)\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": be careful when using iterator protocol because any function side Scheme can return a promise. If you would change\nquoted object literal ",(0,r.jsx)(n.code,{children:"`&()"})," with longhand ",(0,r.jsx)(n.code,{children:"object"})," you will get an error because ",(0,r.jsx)(n.code,{children:"object"})," is async."]}),"\n",(0,r.jsxs)(n.p,{children:["You can abstract the use of iteration protocol with a macro, but to have real ",(0,r.jsx)(n.code,{children:"yield"})," keyword like\nsyntax you need ",(0,r.jsx)(n.code,{children:"call/cc"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["You can also define generators inside JavaScript using ",(0,r.jsx)(n.code,{children:"self.eval"})," (JavaScript global ",(0,r.jsx)(n.code,{children:"eval"}),"):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define gen (self.eval "(async function* gen(time, ...args) {\n function delay(time) {\n return new Promise((resolve) => {\n setTimeout(resolve, time);\n });\n }\n for (let x of args) {\n await delay(time);\n yield x;\n }\n })"))\n\n(iterator->array (gen 100 1 2 3 4 5))\n;; ==> #(1 2 3 4 5)\n'})}),"\n",(0,r.jsx)(n.p,{children:"Here is example of async generator written in JavaScript."}),"\n",(0,r.jsx)(n.h3,{id:"classes",children:"Classes"}),"\n",(0,r.jsxs)(n.p,{children:["In LIPS, you can define JavaScript classes with ",(0,r.jsx)(n.code,{children:"define-class"})," macro:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define-class Person Object\n (constructor (lambda (self name)\n (set! self.name name)))\n (greet (lambda (self)\n (string-append "hello, " self.name))))\n\n(define jack (new Person "Jack"))\n(write jack)\n;; ==> #\n(jack.greet)\n;; ==> "hello, Jack"\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"define-class"})," is macro written in Scheme that uses\n",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes",children:"JavaScript prototypes"})," behind the scene."]}),"\n",(0,r.jsxs)(n.p,{children:["The class always need to have a base class (parent) or you need to use ",(0,r.jsx)(n.code,{children:"null"}),". Classes have explicit\n",(0,r.jsx)(n.code,{children:"self"})," as first argument (similar to Python) but ",(0,r.jsx)(n.code,{children:"this"})," also works inside functions:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! jack.run (lambda () (string-append "run, " this.name)))\n(jack.run)\n;; ==> "run, Jack"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["To create the new instance of a Class, you can use ",(0,r.jsx)(n.code,{children:"new"})," procedure."]}),"\n",(0,r.jsx)(n.p,{children:"You can also manipulate JavaScript prototypes directly:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(write Person.prototype)\n;; ==> #\n(set! Person.prototype.toString (lambda () (string-append "#")))\n(display (jack.toString))\n;; ==> #\n'})}),"\n",(0,r.jsxs)(n.p,{children:["By default toString is not used for representation of objects, but you add representation if you want.\nSee ",(0,r.jsx)(n.a,{href:"/docs/lips/extension#new-homoiconic-data-types",children:"Homoiconic data types"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"nodejs",children:"Node.js"}),"\n",(0,r.jsxs)(n.p,{children:["In Node.js, you can load JavaScript modules with ",(0,r.jsx)(n.code,{children:"require"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define fs (require "fs/promises"))\n(let ((fname "tmp.txt"))\n (fs.writeFile fname "hello LIPS")\n (write (fs.readFile fname "utf-8")))\n;; ==> "hello LIPS"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["In above code, you can see example of ",(0,r.jsx)(n.a,{href:"#automagic-asyncawait",children:"automagic async/await"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["If you have to use callback based API in Node, use\n",(0,r.jsx)(n.a,{href:"https://nodejs.org/api/util.html#utilpromisifyoriginal",children:"promisify function"})," from Module util."]}),"\n",(0,r.jsxs)(n.p,{children:["You can also use the ",(0,r.jsx)(n.code,{children:"Promise"})," constructor yourself:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define fs (require "fs"))\n\n(define-macro (async expr)\n (let ((resolve (gensym "resolve"))\n (reject (gensym "reject")))\n `(new Promise (lambda (,resolve ,reject)\n ,(append expr (list `(lambda (err data)\n ;; Node.js error is null when no error\n (if err\n (,reject err)\n (,resolve data)))))))))\n\n(let ((fname "tmp.txt"))\n (async (fs.writeFile fname "Hello, LIPS!"))\n (write (async (fs.readFile fname "utf-8"))))\n;; ==> "Hello, LIPS!"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["In the above example, we import a regular callback based fs module and use the ",(0,r.jsx)(n.code,{children:"Promise"})," constructor\nabstracted away with a ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/macros#lisp-macros",children:"lisp macro"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"binary-compiler",children:"Binary compiler"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS Scheme have dumb binary compiler. The compiler is a way to compress the LIPS Scheme code and\ncreate binary file that is faster to load. Compiler is use to make bootstrapping faster. The binary\nfile use ",(0,r.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/CBOR",children:"CBOR"})," serialization format that is then compressed\nwith ",(0,r.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/LZJB",children:"LZJB"})," algorithm that is pretty fast. And it can still be\ncompress further with gzip by the HTTP server."]}),"\n",(0,r.jsxs)(n.p,{children:["To compile/compress a file you can use ",(0,r.jsx)(n.code,{children:"-c"})," flag when executing ",(0,r.jsx)(n.code,{children:"lips"})," executable."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ lips -c file.scm\n"})}),"\n",(0,r.jsx)(n.p,{children:"You can then execute the code with:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ lips -c file.xcb\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Will create ",(0,r.jsx)(n.code,{children:"file.xcb"})," in same directory. For smaller files it make not have a difference when\nloading ",(0,r.jsx)(n.code,{children:".xcb"})," or ",(0,r.jsx)(n.code,{children:".scm"})," files."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": directives ",(0,r.jsx)(n.code,{children:"#!fold-case"})," and ",(0,r.jsx)(n.code,{children:"#!no-fold-case"})," work only inside the parser and they are treated\nas comments, so you can't compile the code that have those directives."]})]})}function h(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>t,a:()=>c});var r=s(7294);const a={},i=r.createContext(a);function c(e){const n=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:c(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e1902777.c9bdda11.js b/assets/js/e1902777.c9bdda11.js new file mode 100644 index 00000000..d49b8391 --- /dev/null +++ b/assets/js/e1902777.c9bdda11.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[5609],{5264:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>l});var r=s(5893),a=s(1151);const i={sidebar_position:1,description:"Core LIPS features added on top of Scheme, related to JavaScript"},c="Core features",t={id:"lips/intro",title:"Core features",description:"Core LIPS features added on top of Scheme, related to JavaScript",source:"@site/docs/lips/intro.md",sourceDirName:"lips",slug:"/lips/intro",permalink:"/docs/lips/intro",draft:!1,unlisted:!1,editUrl:"https://github.com/jcubic/lips/tree/master/docs/docs/lips/intro.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,description:"Core LIPS features added on top of Scheme, related to JavaScript"},sidebar:"tutorialSidebar",previous:{title:"LIPS introduction",permalink:"/docs/category/lips-introduction"},next:{title:"Reflection",permalink:"/docs/lips/reflection"}},o={},l=[{value:"Special constants",id:"special-constants",level:2},{value:"Numerical tower",id:"numerical-tower",level:2},{value:"Print procedure",id:"print-procedure",level:2},{value:"Emoji",id:"emoji",level:2},{value:"Macros",id:"macros",level:2},{value:"Gensyms",id:"gensyms",level:3},{value:"Single argument eval",id:"single-argument-eval",level:2},{value:"Procedures",id:"procedures",level:2},{value:"length property",id:"length-property",level:3},{value:"Doc strings",id:"doc-strings",level:2},{value:"Typechecking",id:"typechecking",level:2},{value:"Integration with JavaScript",id:"integration-with-javascript",level:2},{value:"Dot notation",id:"dot-notation",level:3},{value:"Mutating object properties",id:"mutating-object-properties",level:3},{value:"Boxing",id:"boxing",level:3},{value:"Procedures",id:"procedures-1",level:3},{value:"Procedure arity",id:"procedure-arity",level:4},{value:"Helper macros and functions",id:"helper-macros-and-functions",level:3},{value:"Legacy macros and functions",id:"legacy-macros-and-functions",level:4},{value:"Scheme functions",id:"scheme-functions",level:3},{value:"JavaScript functions",id:"javascript-functions",level:3},{value:"Callbacks",id:"callbacks",level:3},{value:"Regular Expressions",id:"regular-expressions",level:3},{value:"Vectors",id:"vectors",level:3},{value:"Object literals",id:"object-literals",level:3},{value:"Automagic async/await",id:"automagic-asyncawait",level:3},{value:"Promise quotation",id:"promise-quotation",level:3},{value:"Promises vs delay expression",id:"promises-vs-delay-expression",level:3},{value:"Exceptions",id:"exceptions",level:3},{value:"JavaScript Generars and iterators",id:"javascript-generars-and-iterators",level:3},{value:"Classes",id:"classes",level:3},{value:"Node.js",id:"nodejs",level:3},{value:"Finding LIPS Scheme directory",id:"finding-lips-scheme-directory",level:3},{value:"Binary compiler",id:"binary-compiler",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"core-features",children:"Core features"}),"\n",(0,r.jsx)(n.h2,{id:"special-constants",children:"Special constants"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define ",(0,r.jsx)(n.code,{children:"#null"})," and ",(0,r.jsx)(n.code,{children:"#void"})," as Parser constants so they can be used inside quoted expressions:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((lst '(#null #void)))\n (write (symbol? (car lst)))\n (newline)\n (write (symbol? (cadr lst)))\n (newline))\n;; ==> #f\n;; ==> #f\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," ",(0,r.jsx)(n.code,{children:"#null"})," is the same as JavaScript ",(0,r.jsx)(n.code,{children:"null"})," value and it's a false value. Similar to\n",(0,r.jsx)(n.a,{href:"https://www.gnu.org/software/kawa/index.html",children:"Kawa Scheme"})," that use ",(0,r.jsx)(n.code,{children:"#!null"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"#void"})," constants is the same as result of ",(0,r.jsx)(n.code,{children:"(value)"})," or ",(0,r.jsx)(n.code,{children:"(if #f #f)"}),". In Scheme it's unspecified value,\nbut in LIPS it's JavaScript undefined. ",(0,r.jsx)(n.code,{children:"#void"})," is not false value."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(eq? (if #f #f) (values))\n;; ==> #t\n"})}),"\n",(0,r.jsx)(n.h2,{id:"numerical-tower",children:"Numerical tower"}),"\n",(0,r.jsx)(n.p,{children:"LIPS support full numerical tower (not yet 100% unit tested):"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"integers - using BitInt"}),"\n",(0,r.jsx)(n.li,{children:"floats - using JavaScript numbers"}),"\n",(0,r.jsx)(n.li,{children:"rationals"}),"\n",(0,r.jsx)(n.li,{children:"complex numbers (that can use integers, floats, or rationals)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"print-procedure",children:"Print procedure"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define helper ",(0,r.jsx)(n.code,{children:"print"})," procedure that display all its arguments with newline after each element."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(print 1 2 3)\n;; ==> 1\n;; ==> 2\n;; ==> 3\n"})}),"\n",(0,r.jsx)(n.h2,{id:"emoji",children:"Emoji"}),"\n",(0,r.jsx)(n.p,{children:"LIPS fully supports all Unicode characters, including emoji:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define smiley #\\\ud83d\ude00)\n(define poo #\\\ud83d\udca9)\n(write (string-append (string smiley) " " (string poo)))\n;; ==> "\ud83d\ude00 \ud83d\udca9"\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can also use them as part of symbols (e.g. as variables name):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define (\u23cf\ufe0f)\n (print "ejecting"))\n(\u23cf\ufe0f)\n;; ==> ejecting\n'})}),"\n",(0,r.jsx)(n.h2,{id:"macros",children:"Macros"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define both Lisp macros and Scheme hygienic macros (",(0,r.jsx)(n.code,{children:"syntax-rules"}),")."]}),"\n",(0,r.jsx)(n.p,{children:"It also implements:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/",children:"SRFI-46"})," which allows changing the ellipsis symbol for nested syntax-rules."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/",children:"SRFI-139"})," which allows defining\n",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/macros#anaphoric-hygienic-macros",children:"anaphoric syntax-rules macros"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-147/",children:"SRFI-147"})," which allows defining a new syntax-rules macros to define syntax-rules macros."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"gensyms",children:"Gensyms"}),"\n",(0,r.jsxs)(n.p,{children:["With lisp macros you can use ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/macros#gensyms",children:"gensyms"}),", they are special Scheme\nsymbols that use JavaScript symbols behind the scene, so they are proven to be unique. Additionally\nyou can use named gensym if you pass string as first argument:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(gensym)\n;; ==> #:g5\n(gensym "sym")\n;; ==> #:sym\n'})}),"\n",(0,r.jsx)(n.h2,{id:"single-argument-eval",children:"Single argument eval"}),"\n",(0,r.jsxs)(n.p,{children:["Eval in LIPS don't require second argument to ",(0,r.jsx)(n.code,{children:"eval"}),". The environment is optional and default\nit's a result of calling ",(0,r.jsx)(n.code,{children:"(interaction-environment)"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(eval '(+ x x))\n;; ==> 20\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(let ((x 20))\n (eval '(- x)))\n;; ==> -10\n"})}),"\n",(0,r.jsx)(n.p,{children:"But you can also use the second arguments:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(let ((x 20))\n (eval '(- x) (current-environment)))\n;; ==> -20\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Read more about ",(0,r.jsx)(n.a,{href:"/docs/lips/environments",children:"LIPS environments"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"procedures",children:"Procedures"}),"\n",(0,r.jsxs)(n.p,{children:["Procedures in LIPS have access additional objects ",(0,r.jsx)(n.code,{children:"arguments"}),", but the have nothing to do with JavaScript.\narguments is an array/vector with calling arguments and it have an object callee which points to the same\nprocedure. So you can create recursive functions with anonymous lambda:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"((lambda (n)\n (if (<= n 0)\n 1\n (* n (arguments.callee (- n 1))))) 10)\n;; ==> 3628800\n"})}),"\n",(0,r.jsx)(n.p,{children:"This is classic factorial function written as lambda without the name."}),"\n",(0,r.jsx)(n.h3,{id:"length-property",children:"length property"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS functions similarly to JavaScript functions also have ",(0,r.jsx)(n.code,{children:"length"})," property that indicate how many\narguments a function accepts. If function get more or less argumenets it's not an error like in Scheme. More arguments are ignored,\nand if less arguments are passed they are ",(0,r.jsx)(n.code,{children:"undefined"})," (",(0,r.jsx)(n.code,{children:"#void"}),")."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define (sum a b c)\n (+ a b c))\n\n(print sum.length)\n;; ==> 3\n"})}),"\n",(0,r.jsx)(n.p,{children:"It return number of number arguments the rest (dot notation) arguments are ignored."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(define (sum a b . rest)\n (apply + a b rest))\n\n(print sum.length)\n;; ==> 3\n(sum 1 2 3 4 5 6)\n;; ==> 21\n"})}),"\n",(0,r.jsx)(n.h2,{id:"doc-strings",children:"Doc strings"}),"\n",(0,r.jsx)(n.p,{children:"Procedures, macros, and variables can have doc strings."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define (factorial n)\n "(factorial n)\n\n Calculate factorial of a given number"\n (if (<= n 0)\n 1\n (* n (factorial (- n 1)))))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can access doc string with ",(0,r.jsx)(n.code,{children:"help"})," procedure or with ",(0,r.jsx)(n.code,{children:"__doc__"})," property."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(write factorial.__doc__)\n"(factorial n)\n\nCalculate factorial of a given number"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["If you define variable or hygienic macro with doc string, the string is hidden (you can access it with ",(0,r.jsx)(n.code,{children:"__doc__"}),"),\nso help is the only way to access it:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define-syntax q\n (syntax-rules ()\n ((_ x) \'x))\n "(q expression)\n\n Macro quote the expression")\n\n(write q.__doc__)\n;; ==> #void\n(help q)\n;; ==> (q expression)\n;; ==>\n;; ==> Macro quote the expression\n'})}),"\n",(0,r.jsx)(n.h2,{id:"typechecking",children:"Typechecking"}),"\n",(0,r.jsx)(n.p,{children:"LIPS do typechecking for all scheme procedures."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(+ "hello" 10)\n;; ==> Expecting number got string\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can incorporate typechecking in your own code:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((x 10))\n (typecheck "let" x "string" 0))\n;; ==> Expecting string got number in expression `let` (argument 0)\n(let ((x "string"))\n (typecheck "let" x "number"))\n;; ==> Expecting number got string in expression `let`\n'})}),"\n",(0,r.jsx)(n.p,{children:"There is also another function to check type of number:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((i 10+10i))\n (typecheck-number "let" i "bigint"))\n;; ==> Expecting bigint got complex in expression `let`\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": In LIPS all integers are BigInts."]}),"\n",(0,r.jsxs)(n.p,{children:["The last typecking function is ",(0,r.jsx)(n.code,{children:"typecheck-args"})," that check if all arguments are of same type."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((number \'(1 10 1/2 10+10i)))\n (typecheck-args "number" "let" number))\n;; ==> #void\n(let ((number \'(1 10 1/2 "string")))\n (typecheck-args "number" "let" number))\n;; ==> Expecting number got string in expression `let` (argument 4)\n'})}),"\n",(0,r.jsx)(n.h2,{id:"integration-with-javascript",children:"Integration with JavaScript"}),"\n",(0,r.jsx)(n.h3,{id:"dot-notation",children:"Dot notation"}),"\n",(0,r.jsx)(n.p,{children:"LIPS allow accessing JavaScript objects with dot notation:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"document.querySelector\n;; ==> #\n"})}),"\n",(0,r.jsx)(n.h3,{id:"mutating-object-properties",children:"Mutating object properties"}),"\n",(0,r.jsxs)(n.p,{children:["You can use dot notation with ",(0,r.jsx)(n.code,{children:"set!"})," to change the value:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(set! self.foo 10)\nself.foo\n"})}),"\n",(0,r.jsxs)(n.p,{children:["top level ",(0,r.jsx)(n.code,{children:"self"})," always points to a global object ",(0,r.jsx)(n.code,{children:"window"})," in browser or ",(0,r.jsx)(n.code,{children:"global"})," in Node."]}),"\n",(0,r.jsxs)(n.p,{children:["There is also older API that still work, which is ",(0,r.jsx)(n.code,{children:"set-obj!"})," but with dot notation you don't\nneed it anymore:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(set-obj! self 'foo 10)\n(display self.foo)\n;; ==> 10\n"})}),"\n",(0,r.jsx)(n.p,{children:"In both platforms you can access global JavaScript objects like normal variables:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! self.greet "hello, LIPS")\n(write greet)\n;; ==> "hello, LIPS"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"boxing",children:"Boxing"}),"\n",(0,r.jsx)(n.p,{children:"LIPS have its own representation for numbers, strings and characters. And when\ninteracting with JavaScript the values may get boxed or unboxed automagically."}),"\n",(0,r.jsxs)(n.p,{children:["You should not confuse boxing with boxes (",(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-111/",children:"SRFI-111"})," and\n",(0,r.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-195",children:"SRFI-195"}),"). LIPS boxes are part of implementation of Scheme\ndata types. And SRFI boxes are containers written in Scheme. Name boxing came from JavaScript, when\nprimitive values are wrapped in objects when you try to use them in object context (like accessing\na property)."]}),"\n",(0,r.jsx)(n.p,{children:"You need to be careful with some of the JavaScript native methods, since they can unbox the value when you don't\nwhen them to be unboxed."}),"\n",(0,r.jsxs)(n.p,{children:["Example is ",(0,r.jsx)(n.code,{children:"Array::push"})," using with native LIPS types:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((v (vector)))\n (v.push 1/2)\n (print v))\n;; ==> #(0.5)\n"})}),"\n",(0,r.jsx)(n.p,{children:"As you can see the rational number got unboxed and converted into JavaScript float numbers.\nUnboxing always can make you loose some information because LIPS types needs to be converted into native JavaScript\ndata types. And JavaScript doesn't have a notion of rationals, there are only floating point numbers, and big ints."}),"\n",(0,r.jsx)(n.h3,{id:"procedures-1",children:"Procedures"}),"\n",(0,r.jsx)(n.p,{children:"LIPS Scheme procedures are JavaScript functions, so you can call them from JavaScript."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! self.greet (lambda () "hello, LIPS"))\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can call this function from JavaScript"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:"console.log(greet());\n// ==> {__string__: 'hello, LIPS'}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note that the value was not automagically unboxed because we are no longer in LIPS Scheme code and LIPS can't access native\nJavaScript. So to get the real a string you need to call ",(0,r.jsx)(n.code,{children:"valueoOf()"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:"console.log(greet().valueOf());\n// ==> hello, LIPS\n"})}),"\n",(0,r.jsx)(n.h4,{id:"procedure-arity",children:"Procedure arity"}),"\n",(0,r.jsx)(n.p,{children:"LIPS don't check the number of argumnents when calling a procedure:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((test (lambda (a b c)\n (print a b c))))\n (test 10))\n;; ==> 10\n;; ==> #void\n;; ==> #void\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The same as with JavaScript if you don't pass an argument it will be undefined. But you still have full compatible with Scheme and use ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/core#variable-number-of-arguments",children:"arguments with variable artity"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((test (lambda (first . rest)\n (apply print first rest))))\n (test 1)\n (test 2 3 4))\n;; ==> 1\n;; ==> 2\n;; ==> 3\n;; ==> 4\n"})}),"\n",(0,r.jsx)(n.h3,{id:"helper-macros-and-functions",children:"Helper macros and functions"}),"\n",(0,r.jsxs)(n.p,{children:["The most useful macro in LIPS (for interacting with JavaScript) is ",(0,r.jsx)(n.code,{children:"--\x3e"})," it acts like a chain of\nmethod calls in JavaScript"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e "this is string" (split " ") (reverse) (join " "))\n;; ==> "string is this"\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can chain methods that return arrays or string and call a method of them. The above expression\nis the same as JavaScript:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:"\"this is string\".split(' ').reverse().join(' ');\n"})}),"\n",(0,r.jsx)(n.p,{children:"With --\x3e you can also gab property of a function:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #/x/ (test.call #/foo/ "foo"))\n;; ==> #t\n(let ((test-bar (--\x3e #/x/ (test.bind #/bar/i))))\n (test-bar "BAR"))\n;; ==> #t\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can also return a function:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define test (--\x3e #/x/ test))\n(test.call #/foo/ "foo")\n;; ==> #t\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Read more about ",(0,r.jsx)(n.a,{href:"https://tinyurl.com/ykvb836s",children:"function::bind"})," and\n",(0,r.jsx)(n.a,{href:"https://tinyurl.com/yc6j7fdh",children:"function::call"})," on ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/",children:"MDN"}),"."]}),"\n",(0,r.jsx)(n.h4,{id:"legacy-macros-and-functions",children:"Legacy macros and functions"}),"\n",(0,r.jsx)(n.p,{children:"There are two legacy macros that are still part of LIPS, but you don't need\nthem most of the time."}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"."})," - dot function was a first way to interact with JavaScript, it allowed to\nget property from an object:"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(. document 'querySelector)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This returned function querySelector from document object in browser. Note that dot a function can only appear\nas first element of the list (it's handled in special way by the parser). In any other place dot is a pair separator,\nsee documentation about ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/data-types#pairs",children:"Pairs in Scheme"}),"."]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".."})," - this is a macro is that simplify usage of ",(0,r.jsx)(n.code,{children:"."})," procedure:"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(.. document.querySelector)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["You still sometimes may want to use this instead of ",(0,r.jsx)(n.code,{children:"--\x3e"})," when you want to get\nproperty from an object returned by expression."]}),"\n",(0,r.jsx)(n.p,{children:"In the old version of LIPS, you have to execute code like this:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'((. document \'querySelector) "body")\n((.. document.querySelector) "body")\n'})}),"\n",(0,r.jsx)(n.p,{children:"The first expression return a Native JavaScript procedure that is then executed."}),"\n",(0,r.jsx)(n.p,{children:"This is equivalent of:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(document.querySelector "body")\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," the only time when you still need ",(0,r.jsx)(n.code,{children:"."})," function is when you want to get the property of\nobject returned by expression."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((style (. (document.querySelector "body") \'style)))\n (set! style.background "red"))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Here we get a ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style",children:"style object"}),"\nfrom ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement",children:"the DOM node"})," without sorting the\nreference to the DOM node."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," because dot notation in symbols is not special syntax you can use code like this:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((x #(1 2 3)))\n (print x.0)\n (print x.1)\n (print x.2))\n;; ==> 1\n;; ==> 2\n;; ==> 3\n"})}),"\n",(0,r.jsx)(n.h3,{id:"scheme-functions",children:"Scheme functions"}),"\n",(0,r.jsx)(n.p,{children:"Scheme functions (lambda's) are JavaScript functions, so you can call them from JavaScript."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! window.foo (lambda () (alert "hello")))\n'})}),"\n",(0,r.jsx)(n.p,{children:"If you define function like this, in browser REPL, you can call it from JavaScript\n(e.g. browser developer console)."}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"TODO"})," Screenshot"]}),"\n",(0,r.jsx)(n.h3,{id:"javascript-functions",children:"JavaScript functions"}),"\n",(0,r.jsx)(n.p,{children:"You can call JavaScript functions from Scheme, the same as you call Scheme procedures:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(document.querySelector "body")\n;; ==> #\n'})}),"\n",(0,r.jsxs)(n.p,{children:["In both browser and Node.js you can execute ",(0,r.jsx)(n.code,{children:"console.log"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(console.log "hello, LIPS")\n;; ==> hello, LIPS\n'})}),"\n",(0,r.jsx)(n.h3,{id:"callbacks",children:"Callbacks"}),"\n",(0,r.jsx)(n.p,{children:"You can use Scheme functions as callbacks to JavaScript functions:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("1" "2" "3") (map string->number))\n;; ==> #(1 +nan.0 +nan.0)\n'})}),"\n",(0,r.jsx)(n.p,{children:"This is classic issue with functions that accept more than one argument. You have samilar issue\nin JavaScript:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:'["1", "2", "3"].map(parseInt)\n// ==> [1, NaN, NaN]\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": the value are different becaseu in Shceme i"]}),"\n",(0,r.jsx)(n.p,{children:"To fix the issue you can\ndefine lambda with single argument:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("1" "2" "3") (map (lambda (str) (string->number str))))\n;; ==> #(1 2 3)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can also use one of functional helpers insprired by ",(0,r.jsx)(n.a,{href:"https://ramdajs.com/",children:"Ramda"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("1" "2" "3") (map (unary string->number)))\n;; ==> #(1 2 3)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"unary"})," ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/core#higher-order-functions",children:"higher-order procedure"})," accept a single\nprocedure and return new procedure that accept only one argument."]}),"\n",(0,r.jsxs)(n.p,{children:["To read more check ",(0,r.jsx)(n.a,{href:"/docs/lips/functional-helpers",children:"Functional helpers"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"WARNING"})," be careful when using scheme callback functions inside JavaScript.\nSince some code may be ",(0,r.jsx)(n.code,{children:"async"})," and your code may break."]}),"\n",(0,r.jsx)(n.p,{children:"Example of procedures that are not wise to use are:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Array::forEach"})," - this function accepts a callaback but because it doesn't return\nanything, LIPS can't automatically await the response, and your code may execute out of order."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"String::replace"})," - this function can accept optional callback and if ",(0,r.jsx)(n.code,{children:"lambda"})," is async\nyou will end up with ",(0,r.jsx)(n.code,{children:"[object Promise]"})," in output string. Any macro or function can return\na promise in LIPS, and if any of the expression inside a function return a Promise, the whole\nfunction return a Promise and become async. Here is example code that demonstrate the problem:"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e "foo bar" (replace "foo" (lambda () (Promise.resolve "xxx"))))\n"[object Promise] bar"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Instead of ",(0,r.jsx)(n.code,{children:"Array::replace"})," you should use LIPS Scheme ",(0,r.jsx)(n.code,{children:"replace"})," procedure that works with async ",(0,r.jsx)(n.code,{children:"lambda"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(replace #/[a-z]+/g (lambda ()\n (Promise.resolve "lips"))\n "foo bar")\n;; ==> "lips lips"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"regular-expressions",children:"Regular Expressions"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS define regular expressions it uses native JavaScript regular expressions.\nAt first, the syntax looked like in JavaScript. It was problematic for the parser\nso you were not able to put space after ",(0,r.jsx)(n.code,{children:"/"})," to distinguish from divide procedure.\nLater, the syntax was renamed into form that start with hash ",(0,r.jsx)(n.code,{children:"#/[0-9]/"}),". The same\nsyntax is used by ",(0,r.jsx)(n.a,{href:"https://practical-scheme.net/gauche/man/gauche-refe/Regular-expressions.html",children:"Gauche"})," implementation. But LIPS supports more flags (same as JavaScript)."]}),"\n",(0,r.jsx)(n.h3,{id:"vectors",children:"Vectors"}),"\n",(0,r.jsxs)(n.p,{children:["In LIPS Scheme vectors are JavaScript arrays. So you can execute methods on them with ",(0,r.jsx)(n.code,{children:"--\x3e"})," macro:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e #("one" "two" "three") (join ":"))\n;; ==> "one:two:three"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"object-literals",children:"Object literals"}),"\n",(0,r.jsxs)(n.p,{children:["In LIPS you can define object literals with ",(0,r.jsx)(n.code,{children:"&"}),"\n",(0,r.jsx)(n.a,{href:"/docs/lips/extension#syntax-extensions",children:"syntax extension"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define obj &(:name "Jack" :age 22))\n(write obj)\n;; ==> &(:name "Jack" :age 22)\n(console.log obj)\n;; ==> { name: \'Jack\', age: 22 }\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can nest object literals and mix them with different object:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define obj &(:name "Jack" :hobbies #("swimming" "programming")))\n(write obj.hobbies)\n;; ==> #("swimming" "programming")\n(console.log obj)\n;; ==> { name: \'Jack\', hobbies: [ \'swiming\', \'programming\' ] }\n'})}),"\n",(0,r.jsx)(n.p,{children:"Object similar to Scheme vectors, are immutable, and everything inside is quoted automatically:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define obj &(:name Jack))\n(write obj)\n;; ==> &(:name "Jack")\n'})}),"\n",(0,r.jsx)(n.p,{children:"But to make it possible to share objects with JavaScript, native LIPS values are automatically unboxed.\nSo instead of symbol representation you get a JavaScript string."}),"\n",(0,r.jsx)(n.p,{children:"You can also use quasiquote with object literals:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define jack (let ((name "Jack")\n (age 22))\n `&(:name ,name :age ,age)))\n(write jack)\n;; ==> &(:name "Jack" :age 22)\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": because of the construction of ",(0,r.jsx)(n.a,{href:"/docs/lips/extension#syntax-extensions",children:"syntax extensions"})," and\n",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/data-types#quasiquote",children:"quasiquote"}),", you can't splice a list inside object literals:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((args (list \':foo "lorem" \':bar "ipsum")))\n `&(,@args))\n;; ==> pair (unquote-splicing args) is not a symbol!\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The reason why this work like this is because, syntax extensions (",(0,r.jsx)(n.code,{children:"&"}),") runs at parse time and LIPS macros are runtime.\nThis may change in the future when ",(0,r.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/169",children:"expansion time will be implemented"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["Objects also have longhand form with ",(0,r.jsx)(n.code,{children:"object"})," macro:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((obj (object :name \'Jack)))\n (write obj))\n;; ==> &(:name "Jack")\n'})}),"\n",(0,r.jsx)(n.p,{children:"But note that object macro is async (return a Promise) so it may be problematic when used it\nwith native JavaScript code."}),"\n",(0,r.jsxs)(n.p,{children:["Using long form ",(0,r.jsx)(n.code,{children:"(object)"})," syntax you can use splicing with help of ",(0,r.jsx)(n.code,{children:"eval"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((args \'(:foo "lorem" :bar "ipsum")))\n (eval `(object ,@args)))\n;; ==> &(:foo "lorem" :bar "ipsum")\n'})}),"\n",(0,r.jsx)(n.p,{children:"The same you can use macros that will return LIPS Scheme code:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define-macro (create-object . args)\n `(object ,@args))\n\n(create-object :foo "lorem" :bar "ipsum")\n;; ==> &(:foo "lorem" :bar "ipsum")\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": this example macro works the same ",(0,r.jsx)(n.code,{children:"object"})," is it's not that useful, but you can create\nmore complex code where you will be able to generate object literals with splicing."]}),"\n",(0,r.jsx)(n.p,{children:"Object literal also have shorthad notation:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((obj &(:x :y)))\n (write obj))\n;; ==> &(:x #void :y #void)\n"})}),"\n",(0,r.jsx)(n.p,{children:"It creates two writtable slots, the rest of the props are read only:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((obj &(:x :y)))\n (set! obj.x 10)\n (set! obj.y 20)\n (write obj))\n;; ==> &(:x 10 :y 20)\n\n(let ((obj &(:x :y)))\n (set! obj.z 20)\n (write obj))\n;; ==> Cannot add property z, object is not extensible\n\n(let ((obj &(:x :y :z 10)))\n (set! obj.z 20)\n (write obj))\n;; ==> Cannot assign to read only property 'z' of object '#'\n"})}),"\n",(0,r.jsx)(n.h3,{id:"automagic-asyncawait",children:"Automagic async/await"}),"\n",(0,r.jsx)(n.p,{children:"LIPS do automatic async/await so it waits for any promise before evaluating\nnext expression."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(Promise.resolve "xxx")\n;; ==> "xxx"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["This simplifies code when using promises, for instance using\n",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API",children:"fetch API"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e (fetch "https://scheme.org.pl/test/") (text) (match #/

([^>]+)<\\/h1>/) 1)\n;; ==> "Scheme is Super Fun"\n'})}),"\n",(0,r.jsx)(n.p,{children:"This is equivalent of JavaScript using async/await:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-javascript",children:'cons res = await fetch("https://scheme.org.pl/test/");\nconst text = await res.text();\ntext.match(/

([^>]+)<\\/h1>/)[1];\n'})}),"\n",(0,r.jsx)(n.h3,{id:"promise-quotation",children:"Promise quotation"}),"\n",(0,r.jsxs)(n.p,{children:["Sometimes you need to process promises as values, for this LIPS support quotation\nof promises. You escape automagic async/await realm and get access to promise as value:\nto quote a promise you use ",(0,r.jsx)(n.code,{children:"'>"}),"\n",(0,r.jsx)(n.a,{href:"/docs/lips/extension#syntax-extensions",children:"syntax extension"}),". To again get into\nautomatic async/await you can use ",(0,r.jsx)(n.code,{children:"(await)"})," procedure"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(let ((promise (--\x3e \'>(fetch "https://scheme.org.pl/test/")\n (then (lambda (res)\n (res.text)))\n (then (lambda (text)\n (. (text.match #/

([^>]+)<\\/h1>/) 1))))))\n (print (await promise)))\n;; ==> Scheme is Super Fun\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," Inside ",(0,r.jsx)(n.code,{children:"then"})," lambda promises are still automagically resolved."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e \'>(Promise.resolve "hello")\n (then (lambda (value)\n (print (string-append value " " (Promise.resolve "LIPS"))))))\n;; ==> hello LIPS\n'})}),"\n",(0,r.jsx)(n.h3,{id:"promises-vs-delay-expression",children:"Promises vs delay expression"}),"\n",(0,r.jsxs)(n.p,{children:["Don't confuse JavaScript promises with ",(0,r.jsx)(n.code,{children:"delay"})," expressions. Their representation looks similar:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(delay 10)\n;; ==> #\n'>(Promise.resolve 10)\n;; ==> #\n"})}),"\n",(0,r.jsxs)(n.p,{children:["You can check if a value is a promise by quoting the expression and using ",(0,r.jsx)(n.code,{children:"promise?"})," predicate:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((a '>10)\n (b '>(Promise.resolve 10)))\n (print (promise? a))\n (print (promise? b)))\n;; ==> #f\n;; ==> #t\n"})}),"\n",(0,r.jsx)(n.h3,{id:"exceptions",children:"Exceptions"}),"\n",(0,r.jsx)(n.p,{children:"LIPS Scheme use javascript exception system. To throw an exception you use:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(throw "This is error")\n;; ==> Error: This is error\n'})}),"\n",(0,r.jsx)(n.p,{children:"or"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(raise (new Error "error"))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"raise"})," procedure throw any object and ",(0,r.jsx)(n.code,{children:"throw"})," wraps the argument in ",(0,r.jsx)(n.code,{children:"new Error"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"You can catch exceptions with LIPS specific try..catch..finally:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(try\n (throw "nasty")\n (catch (e)\n (print (string-append "error " e.message " was caught"))))\n;; ==> error nasty was caught\n'})}),"\n",(0,r.jsx)(n.p,{children:"You can also have finally expression:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(try\n (throw "nasty")\n (catch (e)\n (print (string-append "error " e.message " was caught")))\n (finally\n (print "nothing happened")))\n;; ==> error nasty was caught\n;; ==> nothing happened\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can also define ",(0,r.jsx)(n.code,{children:"finally"})," without ",(0,r.jsx)(n.code,{children:"catch"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(try\n (throw "nasty")\n (finally\n (print "after error")))\n;; ==> after error\n;; ==> nasty\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"})," the order of execution is not expected, but it may change in the future."]}),"\n",(0,r.jsxs)(n.p,{children:["LIPS also define R",(0,r.jsx)("sup",{children:"7"}),"RS guard ",(0,r.jsx)(n.code,{children:"procedure"})," that is just a macro that use try..catch behind the scene:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(guard (e ((list? e) (print (string-append "Error: " (car e)))))\n (raise \'("error")))\n;; ==> Error: error\n'})}),"\n",(0,r.jsx)(n.h3,{id:"javascript-generars-and-iterators",children:"JavaScript Generars and iterators"}),"\n",(0,r.jsxs)(n.p,{children:["Right now there is no way to define JavaScript generators inside LIPS. You can create iterator using\n",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols",children:"iteration prorocol"}),",\nBut to have yield keyword you need ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/continuations",children:"continuations"}),", they are part of the\nLIPS Roadmap."]}),"\n",(0,r.jsx)(n.p,{children:"Here is example of creating iterator in LIPS:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(let ((obj (object))\n (max 5))\n (set-obj! obj Symbol.iterator\n (lambda ()\n (let ((i 0))\n `&(:next ,(lambda ()\n (set! i (+ i 1))\n (if (> i max)\n `&(:done #t)\n `&(:done #f :value ,(/ 1 i))))))))\n (print (iterator->array obj))\n (print (Array.from obj)))\n;; ==> #(1 1/2 1/3 1/4 1/5)\n;; ==> #(1 1/2 1/3 1/4 1/5)\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"Array.from"})," can't be used for every possible case because it will unbox the values (and convert\nrational to float), here it doesn't happen because LIPS don't treat JavaScript iterators in any\nspecial way (it may change in the future). But ",(0,r.jsx)(n.code,{children:"Array.from"})," will convert the array of rationals to\nfloat if used on normal vector:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:"(Array.from #(1/2 1/3 1/4 1/5))\n;; ==> #(0.5 0.3333333333333333 0.25 0.2)\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": be careful when using iterator protocol because any function side Scheme can return a promise. If you would change\nquoted object literal ",(0,r.jsx)(n.code,{children:"`&()"})," with longhand ",(0,r.jsx)(n.code,{children:"object"})," you will get an error because ",(0,r.jsx)(n.code,{children:"object"})," is async."]}),"\n",(0,r.jsxs)(n.p,{children:["You can abstract the use of iteration protocol with a macro, but to have real ",(0,r.jsx)(n.code,{children:"yield"})," keyword like\nsyntax you need ",(0,r.jsx)(n.code,{children:"call/cc"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["You can also define generators inside JavaScript using ",(0,r.jsx)(n.code,{children:"self.eval"})," (JavaScript global ",(0,r.jsx)(n.code,{children:"eval"}),"):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define gen (self.eval "(async function* gen(time, ...args) {\n function delay(time) {\n return new Promise((resolve) => {\n setTimeout(resolve, time);\n });\n }\n for (let x of args) {\n await delay(time);\n yield x;\n }\n })"))\n\n(iterator->array (gen 100 1 2 3 4 5))\n;; ==> #(1 2 3 4 5)\n'})}),"\n",(0,r.jsx)(n.p,{children:"Here is example of async generator written in JavaScript."}),"\n",(0,r.jsx)(n.h3,{id:"classes",children:"Classes"}),"\n",(0,r.jsxs)(n.p,{children:["In LIPS, you can define JavaScript classes with ",(0,r.jsx)(n.code,{children:"define-class"})," macro:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define-class Person Object\n (constructor (lambda (self name)\n (set! self.name name)))\n (greet (lambda (self)\n (string-append "hello, " self.name))))\n\n(define jack (new Person "Jack"))\n(write jack)\n;; ==> #\n(jack.greet)\n;; ==> "hello, Jack"\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"define-class"})," is macro written in Scheme that uses\n",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes",children:"JavaScript prototypes"})," behind the scene."]}),"\n",(0,r.jsxs)(n.p,{children:["The class always need to have a base class (parent) or you need to use ",(0,r.jsx)(n.code,{children:"null"}),". Classes have explicit\n",(0,r.jsx)(n.code,{children:"self"})," as first argument (similar to Python) but ",(0,r.jsx)(n.code,{children:"this"})," also works inside functions:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(set! jack.run (lambda () (string-append "run, " this.name)))\n(jack.run)\n;; ==> "run, Jack"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["To create the new instance of a Class, you can use ",(0,r.jsx)(n.code,{children:"new"})," procedure."]}),"\n",(0,r.jsx)(n.p,{children:"You can also manipulate JavaScript prototypes directly:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(write Person.prototype)\n;; ==> #\n(set! Person.prototype.toString (lambda () (string-append "#")))\n(display (jack.toString))\n;; ==> #\n'})}),"\n",(0,r.jsxs)(n.p,{children:["By default toString is not used for representation of objects, but you add representation if you want.\nSee ",(0,r.jsx)(n.a,{href:"/docs/lips/extension#new-homoiconic-data-types",children:"Homoiconic data types"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"nodejs",children:"Node.js"}),"\n",(0,r.jsxs)(n.p,{children:["In Node.js, you can load JavaScript modules with ",(0,r.jsx)(n.code,{children:"require"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define fs (require "fs/promises"))\n(let ((fname "tmp.txt"))\n (fs.writeFile fname "hello LIPS")\n (write (fs.readFile fname "utf-8")))\n;; ==> "hello LIPS"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["In above code, you can see example of ",(0,r.jsx)(n.a,{href:"#automagic-asyncawait",children:"automagic async/await"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["If you have to use callback based API in Node, use\n",(0,r.jsx)(n.a,{href:"https://nodejs.org/api/util.html#utilpromisifyoriginal",children:"promisify function"})," from Module util."]}),"\n",(0,r.jsxs)(n.p,{children:["You can also use the ",(0,r.jsx)(n.code,{children:"Promise"})," constructor yourself:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(define fs (require "fs"))\n\n(define-macro (async expr)\n (let ((resolve (gensym "resolve"))\n (reject (gensym "reject")))\n `(new Promise (lambda (,resolve ,reject)\n ,(append expr (list `(lambda (err data)\n ;; Node.js error is null when no error\n (if err\n (,reject err)\n (,resolve data)))))))))\n\n(let ((fname "tmp.txt"))\n (async (fs.writeFile fname "Hello, LIPS!"))\n (write (async (fs.readFile fname "utf-8"))))\n;; ==> "Hello, LIPS!"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["In the above example, we import a regular callback based fs module and use the ",(0,r.jsx)(n.code,{children:"Promise"})," constructor\nabstracted away with a ",(0,r.jsx)(n.a,{href:"/docs/scheme-intro/macros#lisp-macros",children:"lisp macro"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"finding-lips-scheme-directory",children:"Finding LIPS Scheme directory"}),"\n",(0,r.jsxs)(n.p,{children:["With help from ",(0,r.jsx)(n.code,{children:"(require.resolve)"})," you can get the path of the root directory of LIPS Scheme:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-scheme",children:'(--\x3e (require.resolve "@jcubic/lips") (replace #/dist\\/[^\\/]+$/ ""))\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Node.js REPL load lips from Common.jS file and ",(0,r.jsx)(n.code,{children:"require.resolve"})," returns path to file\n",(0,r.jsx)(n.code,{children:"dist/lips.cjs"}),", by removing with with String::replace and regular expression you can the real path\nto the root of the LIPS Scheme."]}),"\n",(0,r.jsx)(n.h2,{id:"binary-compiler",children:"Binary compiler"}),"\n",(0,r.jsxs)(n.p,{children:["LIPS Scheme have dumb binary compiler. The compiler is a way to compress the LIPS Scheme code and\ncreate binary file that is faster to load. Compiler is use to make bootstrapping faster. The binary\nfile use ",(0,r.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/CBOR",children:"CBOR"})," serialization format that is then compressed\nwith ",(0,r.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/LZJB",children:"LZJB"})," algorithm that is pretty fast. And it can still be\ncompress further with gzip by the HTTP server."]}),"\n",(0,r.jsxs)(n.p,{children:["To compile/compress a file you can use ",(0,r.jsx)(n.code,{children:"-c"})," flag when executing ",(0,r.jsx)(n.code,{children:"lips"})," executable."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ lips -c file.scm\n"})}),"\n",(0,r.jsx)(n.p,{children:"You can then execute the code with:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ lips -c file.xcb\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Will create ",(0,r.jsx)(n.code,{children:"file.xcb"})," in same directory. For smaller files it make not have a difference when\nloading ",(0,r.jsx)(n.code,{children:".xcb"})," or ",(0,r.jsx)(n.code,{children:".scm"})," files."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"NOTE"}),": directives ",(0,r.jsx)(n.code,{children:"#!fold-case"})," and ",(0,r.jsx)(n.code,{children:"#!no-fold-case"})," work only inside the parser and they are treated\nas comments, so you can't compile the code that have those directives."]})]})}function h(e={}){const{wrapper:n}={...(0,a.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>t,a:()=>c});var r=s(7294);const a={},i=r.createContext(a);function c(e){const n=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:c(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.ddef3ef4.js b/assets/js/runtime~main.59481896.js similarity index 98% rename from assets/js/runtime~main.ddef3ef4.js rename to assets/js/runtime~main.59481896.js index 351b6aa8..caa69acb 100644 --- a/assets/js/runtime~main.ddef3ef4.js +++ b/assets/js/runtime~main.59481896.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,f,c,t,r={},d={};function b(e){var a=d[e];if(void 0!==a)return a.exports;var f=d[e]={exports:{}};return r[e].call(f.exports,f,f.exports,b),f.exports}b.m=r,e=[],b.O=(a,f,c,t)=>{if(!f){var r=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](f[o])))?f.splice(o--,1):(d=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[f,c,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var r={};a=a||[null,f({}),f([]),f(f)];for(var d=2&c&&e;"object"==typeof d&&!~a.indexOf(d);d=f(d))Object.getOwnPropertyNames(d).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,b.d(t,r),t},b.d=(e,a)=>{for(var f in a)b.o(a,f)&&!b.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,f)=>(b.f[f](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",81:"2abfd7a8",533:"b2b675dd",743:"7e736cac",1070:"f196f4a4",1113:"e511e452",1208:"3828c8cd",1317:"75505f57",1477:"b2f554cd",1652:"ea13dd3a",1677:"0a637f08",1713:"a7023ddc",2535:"814f3328",2553:"6878938b",2813:"4b1723f1",2822:"35ee46b0",3085:"1f391b9e",3089:"a6aa9e1f",3237:"1df93b7f",3604:"9ede617c",3608:"9e4087bc",4013:"01a85c17",4015:"69aa9e93",4368:"a94703ab",4699:"ab461798",4985:"14a48451",5460:"9abc7bc7",5564:"468f2e1c",5609:"e1902777",5747:"726afaaf",6103:"ccc49370",6143:"1f27c5d1",6296:"c74dcec5",7018:"413466e5",7184:"68243087",7393:"acecf23e",7414:"393be207",7836:"840797c7",7868:"aa178e2b",7903:"db96436e",7918:"17896441",7953:"f724a01c",8071:"f2e31a35",8097:"4f7497d7",8424:"5ad8d976",8518:"a7bd4aaa",8610:"6875c492",9195:"d969d8ea",9242:"c71491fd",9301:"430f917c",9342:"df5a86e1",9661:"5e95c892",9671:"0e384e19",9817:"14eb3368"}[e]||e)+"."+{53:"cc6240be",81:"eaf1209f",533:"7f33185e",743:"41e22d1d",1070:"4d17d4a0",1113:"6dce99c6",1208:"aa6ba2aa",1317:"519f4209",1477:"92ae2c22",1652:"e9dd3f0f",1677:"61ff06c6",1713:"f57aae3f",1772:"205fa78b",2535:"33be7cdd",2553:"62200649",2813:"7994837a",2822:"5499b20c",3085:"6e4b1596",3089:"ca60c0b4",3237:"7bff3f57",3604:"9d811c06",3608:"eb64b0cc",4013:"0d6af7b9",4015:"00e22eaa",4368:"fac9076a",4699:"e445eee8",4985:"b2bb271d",5005:"facea533",5460:"58965eb1",5564:"1eb5cbc8",5609:"57d1fa3f",5747:"5e9ff151",6103:"75bf7d8f",6143:"4d1e30de",6296:"2757b8e1",6705:"8d1cee0d",7018:"5b84004c",7184:"0f23da7a",7393:"3caaec2f",7414:"6bb4bbad",7534:"5a903753",7836:"60904e28",7868:"f31d8ce2",7903:"8da5bafb",7918:"af71c726",7953:"087dbc0b",8071:"eff52960",8097:"07ed6383",8424:"f15ddef4",8518:"b2f1f87c",8610:"54a03b73",9195:"6ce6b63f",9242:"11363cc6",9301:"756863bd",9342:"5a8b1f83",9386:"eb7dae53",9661:"daee7819",9671:"4a2ae178",9817:"131961d5"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},t="new-docs:",b.l=(e,a,f,r)=>{if(c[e])c[e].push(a);else{var d,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i{d.onerror=d.onload=null,clearTimeout(s);var t=c[e];if(delete c[e],d.parentNode&&d.parentNode.removeChild(d),t&&t.forEach((e=>e(f))),a)return a(f)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),o&&document.head.appendChild(d)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"7918",68243087:"7184","935f2afb":"53","2abfd7a8":"81",b2b675dd:"533","7e736cac":"743",f196f4a4:"1070",e511e452:"1113","3828c8cd":"1208","75505f57":"1317",b2f554cd:"1477",ea13dd3a:"1652","0a637f08":"1677",a7023ddc:"1713","814f3328":"2535","6878938b":"2553","4b1723f1":"2813","35ee46b0":"2822","1f391b9e":"3085",a6aa9e1f:"3089","1df93b7f":"3237","9ede617c":"3604","9e4087bc":"3608","01a85c17":"4013","69aa9e93":"4015",a94703ab:"4368",ab461798:"4699","14a48451":"4985","9abc7bc7":"5460","468f2e1c":"5564",e1902777:"5609","726afaaf":"5747",ccc49370:"6103","1f27c5d1":"6143",c74dcec5:"6296","413466e5":"7018",acecf23e:"7393","393be207":"7414","840797c7":"7836",aa178e2b:"7868",db96436e:"7903",f724a01c:"7953",f2e31a35:"8071","4f7497d7":"8097","5ad8d976":"8424",a7bd4aaa:"8518","6875c492":"8610",d969d8ea:"9195",c71491fd:"9242","430f917c":"9301",df5a86e1:"9342","5e95c892":"9661","0e384e19":"9671","14eb3368":"9817"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(a,f)=>{var c=b.o(e,a)?e[a]:void 0;if(0!==c)if(c)f.push(c[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var t=new Promise(((f,t)=>c=e[a]=[f,t]));f.push(c[2]=t);var r=b.p+b.u(a),d=new Error;b.l(r,(f=>{if(b.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var t=f&&("load"===f.type?"missing":f.type),r=f&&f.target&&f.target.src;d.message="Loading chunk "+a+" failed.\n("+t+": "+r+")",d.name="ChunkLoadError",d.type=t,d.request=r,c[1](d)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,f)=>{var c,t,r=f[0],d=f[1],o=f[2],n=0;if(r.some((a=>0!==e[a]))){for(c in d)b.o(d,c)&&(b.m[c]=d[c]);if(o)var i=o(b)}for(a&&a(f);n{"use strict";var e,a,f,c,t,r={},d={};function b(e){var a=d[e];if(void 0!==a)return a.exports;var f=d[e]={exports:{}};return r[e].call(f.exports,f,f.exports,b),f.exports}b.m=r,e=[],b.O=(a,f,c,t)=>{if(!f){var r=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](f[o])))?f.splice(o--,1):(d=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[f,c,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var r={};a=a||[null,f({}),f([]),f(f)];for(var d=2&c&&e;"object"==typeof d&&!~a.indexOf(d);d=f(d))Object.getOwnPropertyNames(d).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,b.d(t,r),t},b.d=(e,a)=>{for(var f in a)b.o(a,f)&&!b.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,f)=>(b.f[f](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",81:"2abfd7a8",533:"b2b675dd",743:"7e736cac",1070:"f196f4a4",1113:"e511e452",1208:"3828c8cd",1317:"75505f57",1477:"b2f554cd",1652:"ea13dd3a",1677:"0a637f08",1713:"a7023ddc",2535:"814f3328",2553:"6878938b",2813:"4b1723f1",2822:"35ee46b0",3085:"1f391b9e",3089:"a6aa9e1f",3237:"1df93b7f",3604:"9ede617c",3608:"9e4087bc",4013:"01a85c17",4015:"69aa9e93",4368:"a94703ab",4699:"ab461798",4985:"14a48451",5460:"9abc7bc7",5564:"468f2e1c",5609:"e1902777",5747:"726afaaf",6103:"ccc49370",6143:"1f27c5d1",6296:"c74dcec5",7018:"413466e5",7184:"68243087",7393:"acecf23e",7414:"393be207",7836:"840797c7",7868:"aa178e2b",7903:"db96436e",7918:"17896441",7953:"f724a01c",8071:"f2e31a35",8097:"4f7497d7",8424:"5ad8d976",8518:"a7bd4aaa",8610:"6875c492",9195:"d969d8ea",9242:"c71491fd",9301:"430f917c",9342:"df5a86e1",9661:"5e95c892",9671:"0e384e19",9817:"14eb3368"}[e]||e)+"."+{53:"cc6240be",81:"eaf1209f",533:"7f33185e",743:"41e22d1d",1070:"4d17d4a0",1113:"6dce99c6",1208:"aa6ba2aa",1317:"519f4209",1477:"92ae2c22",1652:"e9dd3f0f",1677:"61ff06c6",1713:"f57aae3f",1772:"205fa78b",2535:"33be7cdd",2553:"62200649",2813:"7994837a",2822:"5499b20c",3085:"6e4b1596",3089:"ca60c0b4",3237:"7bff3f57",3604:"9d811c06",3608:"eb64b0cc",4013:"0d6af7b9",4015:"00e22eaa",4368:"fac9076a",4699:"e445eee8",4985:"b2bb271d",5005:"facea533",5460:"58965eb1",5564:"1eb5cbc8",5609:"c9bdda11",5747:"5e9ff151",6103:"75bf7d8f",6143:"4d1e30de",6296:"2757b8e1",6705:"8d1cee0d",7018:"5b84004c",7184:"0f23da7a",7393:"3caaec2f",7414:"6bb4bbad",7534:"5a903753",7836:"60904e28",7868:"f31d8ce2",7903:"8da5bafb",7918:"af71c726",7953:"087dbc0b",8071:"eff52960",8097:"07ed6383",8424:"f15ddef4",8518:"b2f1f87c",8610:"54a03b73",9195:"6ce6b63f",9242:"11363cc6",9301:"756863bd",9342:"5a8b1f83",9386:"eb7dae53",9661:"daee7819",9671:"4a2ae178",9817:"131961d5"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},t="new-docs:",b.l=(e,a,f,r)=>{if(c[e])c[e].push(a);else{var d,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i{d.onerror=d.onload=null,clearTimeout(s);var t=c[e];if(delete c[e],d.parentNode&&d.parentNode.removeChild(d),t&&t.forEach((e=>e(f))),a)return a(f)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),o&&document.head.appendChild(d)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"7918",68243087:"7184","935f2afb":"53","2abfd7a8":"81",b2b675dd:"533","7e736cac":"743",f196f4a4:"1070",e511e452:"1113","3828c8cd":"1208","75505f57":"1317",b2f554cd:"1477",ea13dd3a:"1652","0a637f08":"1677",a7023ddc:"1713","814f3328":"2535","6878938b":"2553","4b1723f1":"2813","35ee46b0":"2822","1f391b9e":"3085",a6aa9e1f:"3089","1df93b7f":"3237","9ede617c":"3604","9e4087bc":"3608","01a85c17":"4013","69aa9e93":"4015",a94703ab:"4368",ab461798:"4699","14a48451":"4985","9abc7bc7":"5460","468f2e1c":"5564",e1902777:"5609","726afaaf":"5747",ccc49370:"6103","1f27c5d1":"6143",c74dcec5:"6296","413466e5":"7018",acecf23e:"7393","393be207":"7414","840797c7":"7836",aa178e2b:"7868",db96436e:"7903",f724a01c:"7953",f2e31a35:"8071","4f7497d7":"8097","5ad8d976":"8424",a7bd4aaa:"8518","6875c492":"8610",d969d8ea:"9195",c71491fd:"9242","430f917c":"9301",df5a86e1:"9342","5e95c892":"9661","0e384e19":"9671","14eb3368":"9817"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(a,f)=>{var c=b.o(e,a)?e[a]:void 0;if(0!==c)if(c)f.push(c[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var t=new Promise(((f,t)=>c=e[a]=[f,t]));f.push(c[2]=t);var r=b.p+b.u(a),d=new Error;b.l(r,(f=>{if(b.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var t=f&&("load"===f.type?"missing":f.type),r=f&&f.target&&f.target.src;d.message="Loading chunk "+a+" failed.\n("+t+": "+r+")",d.name="ChunkLoadError",d.type=t,d.request=r,c[1](d)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,f)=>{var c,t,r=f[0],d=f[1],o=f[2],n=0;if(r.some((a=>0!==e[a]))){for(c in d)b.o(d,c)&&(b.m[c]=d[c]);if(o)var i=o(b)}for(a&&a(f);n Archive | LIPS Scheme - + diff --git a/blog/emacs-scheme-regex/index.html b/blog/emacs-scheme-regex/index.html index 5352a055..22d05634 100644 --- a/blog/emacs-scheme-regex/index.html +++ b/blog/emacs-scheme-regex/index.html @@ -4,7 +4,7 @@ Scheme Regex literals in Emacs | LIPS Scheme - + diff --git a/blog/index.html b/blog/index.html index 1168cc45..cf96c5d0 100644 --- a/blog/index.html +++ b/blog/index.html @@ -4,7 +4,7 @@ Blog | LIPS Scheme - + diff --git a/blog/lips-history/index.html b/blog/lips-history/index.html index 6f64628f..e9212f79 100644 --- a/blog/lips-history/index.html +++ b/blog/lips-history/index.html @@ -4,7 +4,7 @@ LIPS History | LIPS Scheme - + diff --git a/blog/tags/emacs/index.html b/blog/tags/emacs/index.html index 1929a081..d20c50fc 100644 --- a/blog/tags/emacs/index.html +++ b/blog/tags/emacs/index.html @@ -4,7 +4,7 @@ One post tagged with "emacs" | LIPS Scheme - + diff --git a/blog/tags/history/index.html b/blog/tags/history/index.html index 58a213db..ec1788fe 100644 --- a/blog/tags/history/index.html +++ b/blog/tags/history/index.html @@ -4,7 +4,7 @@ One post tagged with "history" | LIPS Scheme - + diff --git a/blog/tags/index.html b/blog/tags/index.html index ee946a16..fad1ad1f 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -4,7 +4,7 @@ Tags | LIPS Scheme - + diff --git a/blog/tags/lips/index.html b/blog/tags/lips/index.html index 9734a066..74a96957 100644 --- a/blog/tags/lips/index.html +++ b/blog/tags/lips/index.html @@ -4,7 +4,7 @@ One post tagged with "lips" | LIPS Scheme - + diff --git a/blog/tags/scheme/index.html b/blog/tags/scheme/index.html index 18690e1e..91d0b735 100644 --- a/blog/tags/scheme/index.html +++ b/blog/tags/scheme/index.html @@ -4,7 +4,7 @@ 2 posts tagged with "scheme" | LIPS Scheme - + diff --git a/docs/category/introduction-to-scheme/index.html b/docs/category/introduction-to-scheme/index.html index 5310bc91..4297e15f 100644 --- a/docs/category/introduction-to-scheme/index.html +++ b/docs/category/introduction-to-scheme/index.html @@ -4,7 +4,7 @@ Introduction to Scheme | LIPS Scheme - + diff --git a/docs/category/lips-introduction/index.html b/docs/category/lips-introduction/index.html index 9e41532d..ed341bbe 100644 --- a/docs/category/lips-introduction/index.html +++ b/docs/category/lips-introduction/index.html @@ -4,7 +4,7 @@ LIPS introduction | LIPS Scheme - + diff --git a/docs/intro/index.html b/docs/intro/index.html index bccf1f95..802b6c62 100644 --- a/docs/intro/index.html +++ b/docs/intro/index.html @@ -4,7 +4,7 @@ Getting Started | LIPS Scheme - + diff --git a/docs/lips/REPL/index.html b/docs/lips/REPL/index.html index 4b7b91c3..43e277a4 100644 --- a/docs/lips/REPL/index.html +++ b/docs/lips/REPL/index.html @@ -4,7 +4,7 @@ REPL | LIPS Scheme - + diff --git a/docs/lips/environments/index.html b/docs/lips/environments/index.html index 90b413f4..f8616061 100644 --- a/docs/lips/environments/index.html +++ b/docs/lips/environments/index.html @@ -4,7 +4,7 @@ Environments | LIPS Scheme - + diff --git a/docs/lips/extension/index.html b/docs/lips/extension/index.html index 9468f364..82d5bb9d 100644 --- a/docs/lips/extension/index.html +++ b/docs/lips/extension/index.html @@ -4,7 +4,7 @@ Extending LIPS | LIPS Scheme - + diff --git a/docs/lips/functional-helpers/index.html b/docs/lips/functional-helpers/index.html index 7ad4b766..9451a44c 100644 --- a/docs/lips/functional-helpers/index.html +++ b/docs/lips/functional-helpers/index.html @@ -4,7 +4,7 @@ Functional and other utils | LIPS Scheme - + diff --git a/docs/lips/intro/index.html b/docs/lips/intro/index.html index 423414d3..002aff63 100644 --- a/docs/lips/intro/index.html +++ b/docs/lips/intro/index.html @@ -4,7 +4,7 @@ Core features | LIPS Scheme - + @@ -676,6 +676,13 @@

Node.js

In the above example, we import a regular callback based fs module and use the Promise constructor abstracted away with a lisp macro.

+

Finding LIPS Scheme directory​

+

With help from (require.resolve) you can get the path of the root directory of LIPS Scheme:

+
(--> (require.resolve "@jcubic/lips") (replace #/dist\/[^\/]+$/ ""))
+
+

Node.js REPL load lips from Common.jS file and require.resolve returns path to file +dist/lips.cjs, by removing with with String::replace and regular expression you can the real path +to the root of the LIPS Scheme.

Binary compiler​

LIPS Scheme have dumb binary compiler. The compiler is a way to compress the LIPS Scheme code and create binary file that is faster to load. Compiler is use to make bootstrapping faster. The binary @@ -691,6 +698,6 @@

Binary compi

Will create file.xcb in same directory. For smaller files it make not have a difference when loading .xcb or .scm files.

NOTE: directives #!fold-case and #!no-fold-case work only inside the parser and they are treated -as comments, so you can't compile the code that have those directives.

+as comments, so you can't compile the code that have those directives.

\ No newline at end of file diff --git a/docs/lips/reflection/index.html b/docs/lips/reflection/index.html index d171339d..d01a4596 100644 --- a/docs/lips/reflection/index.html +++ b/docs/lips/reflection/index.html @@ -4,7 +4,7 @@ Reflection | LIPS Scheme - + diff --git a/docs/lips/sxml/index.html b/docs/lips/sxml/index.html index 4eccde55..16512c79 100644 --- a/docs/lips/sxml/index.html +++ b/docs/lips/sxml/index.html @@ -4,7 +4,7 @@ SXML (e.g. for React) | LIPS Scheme - + diff --git a/docs/scheme-intro/continuations/index.html b/docs/scheme-intro/continuations/index.html index 02051f70..f08e5f1e 100644 --- a/docs/scheme-intro/continuations/index.html +++ b/docs/scheme-intro/continuations/index.html @@ -4,7 +4,7 @@ Continuations | LIPS Scheme - + diff --git a/docs/scheme-intro/core/index.html b/docs/scheme-intro/core/index.html index b1b7f2d1..2f383796 100644 --- a/docs/scheme-intro/core/index.html +++ b/docs/scheme-intro/core/index.html @@ -4,7 +4,7 @@ Core of Scheme | LIPS Scheme - + diff --git a/docs/scheme-intro/data-types/index.html b/docs/scheme-intro/data-types/index.html index b70aeb8c..f30e2b0b 100644 --- a/docs/scheme-intro/data-types/index.html +++ b/docs/scheme-intro/data-types/index.html @@ -4,7 +4,7 @@ Data Types | LIPS Scheme - + diff --git a/docs/scheme-intro/input-output/index.html b/docs/scheme-intro/input-output/index.html index 2ae43775..1afe3493 100644 --- a/docs/scheme-intro/input-output/index.html +++ b/docs/scheme-intro/input-output/index.html @@ -4,7 +4,7 @@ Input and Output | LIPS Scheme - + diff --git a/docs/scheme-intro/macros/index.html b/docs/scheme-intro/macros/index.html index 5d68e0d5..ac5d0c20 100644 --- a/docs/scheme-intro/macros/index.html +++ b/docs/scheme-intro/macros/index.html @@ -4,7 +4,7 @@ Macros | LIPS Scheme - + diff --git a/docs/scheme-intro/next-step/index.html b/docs/scheme-intro/next-step/index.html index 624b1ec2..32ee44c8 100644 --- a/docs/scheme-intro/next-step/index.html +++ b/docs/scheme-intro/next-step/index.html @@ -4,7 +4,7 @@ What Next | LIPS Scheme - + diff --git a/docs/scheme-intro/streams/index.html b/docs/scheme-intro/streams/index.html index ee4824db..ffe89790 100644 --- a/docs/scheme-intro/streams/index.html +++ b/docs/scheme-intro/streams/index.html @@ -4,7 +4,7 @@ Streams | LIPS Scheme - + diff --git a/docs/scheme-intro/what-is-lisp/index.html b/docs/scheme-intro/what-is-lisp/index.html index 9d555bf2..6089353e 100644 --- a/docs/scheme-intro/what-is-lisp/index.html +++ b/docs/scheme-intro/what-is-lisp/index.html @@ -4,7 +4,7 @@ What is Lisp and Scheme | LIPS Scheme - + diff --git a/index.html b/index.html index 85d2ee5c..602bcada 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Powerful Scheme interpreter in JavaScript | LIPS Scheme - + diff --git a/markdown-page/index.html b/markdown-page/index.html index dac42bde..2487cd62 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -4,7 +4,7 @@ Markdown page example | LIPS Scheme - + diff --git a/reference/index.html b/reference/index.html index 2a4b9276..06b80248 100644 --- a/reference/index.html +++ b/reference/index.html @@ -4,7 +4,7 @@ LIPS Scheme | LIPS Scheme - + diff --git a/screenshooter/index.html b/screenshooter/index.html index 9d91abb5..f83a01c6 100644 --- a/screenshooter/index.html +++ b/screenshooter/index.html @@ -4,7 +4,7 @@ LIPS Scheme | LIPS Scheme - +