Page Not Found | LIPS Scheme
-
+
diff --git a/assets/js/0522e7aa.9d4051dd.js b/assets/js/0522e7aa.9d4051dd.js
new file mode 100644
index 00000000..89268913
--- /dev/null
+++ b/assets/js/0522e7aa.9d4051dd.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[6580],{6139:e=>{e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Introduction to Scheme","description":"Scheme Tutorial, that teaches you basics of Scheme Programming Language. This tutorial explain all the features of Scheme and it\'s not specific of LIPS Scheme. It mostly describes R7RS standard of Scheme.","slug":"/category/introduction-to-scheme","permalink":"/docs/category/introduction-to-scheme","sidebar":"tutorialSidebar","navigation":{"previous":{"title":"Getting Started","permalink":"/docs/intro"},"next":{"title":"What is Lisp and Scheme?","permalink":"/docs/scheme-intro/what-is-lisp"}}}}')}}]);
\ No newline at end of file
diff --git a/assets/js/0522e7aa.d85eb94c.js b/assets/js/0522e7aa.d85eb94c.js
deleted file mode 100644
index 09e53bad..00000000
--- a/assets/js/0522e7aa.d85eb94c.js
+++ /dev/null
@@ -1 +0,0 @@
-"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[6580],{6139:e=>{e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Introduction to Scheme","slug":"/category/introduction-to-scheme","permalink":"/docs/category/introduction-to-scheme","sidebar":"tutorialSidebar","navigation":{"previous":{"title":"Getting Started","permalink":"/docs/intro"},"next":{"title":"What is Lisp and Scheme?","permalink":"/docs/scheme-intro/what-is-lisp"}}}}')}}]);
\ No newline at end of file
diff --git a/assets/js/d969d8ea.b9446a1b.js b/assets/js/d969d8ea.47320509.js
similarity index 88%
rename from assets/js/d969d8ea.b9446a1b.js
rename to assets/js/d969d8ea.47320509.js
index fd12f426..d03128fd 100644
--- a/assets/js/d969d8ea.b9446a1b.js
+++ b/assets/js/d969d8ea.47320509.js
@@ -1 +1 @@
-"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[9263],{2259:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"scheme-intro/data-types","title":"Data Types","description":"All different data types you can have in Scheme","source":"@site/docs/scheme-intro/data-types.md","sourceDirName":"scheme-intro","slug":"/scheme-intro/data-types","permalink":"/docs/scheme-intro/data-types","draft":false,"unlisted":false,"editUrl":"https://github.com/LIPS-scheme/lips/tree/master/docs/docs/scheme-intro/data-types.md","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"description":"All different data types you can have in Scheme"},"sidebar":"tutorialSidebar","previous":{"title":"What is Lisp and Scheme?","permalink":"/docs/scheme-intro/what-is-lisp"},"next":{"title":"Core of Scheme","permalink":"/docs/scheme-intro/core"}}');var t=n(4848),c=n(8453);const r={sidebar_position:2,description:"All different data types you can have in Scheme"},a="Data Types",l={},o=[{value:"Numbers",id:"numbers",level:2},{value:"Boolean values",id:"boolean-values",level:2},{value:"Strings",id:"strings",level:2},{value:"Characters",id:"characters",level:2},{value:"Symbols",id:"symbols",level:2},{value:"Comments",id:"comments",level:2},{value:"Empty list",id:"empty-list",level:2},{value:"Pairs",id:"pairs",level:2},{value:"List Modification",id:"list-modification",level:2},{value:"Improper list",id:"improper-list",level:2},{value:"Cycles",id:"cycles",level:2},{value:"Vectors",id:"vectors",level:2},{value:"Quotations",id:"quotations",level:2},{value:"Base Quote",id:"base-quote",level:3},{value:"Quasiquote",id:"quasiquote",level:3},{value:"Quotation of quotation",id:"quotation-of-quotation",level:3},{value:"Quotation on vector literals",id:"quotation-on-vector-literals",level:3},{value:"Special symbols",id:"special-symbols",level:2}];function d(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,c.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.header,{children:(0,t.jsx)(s.h1,{id:"data-types",children:"Data Types"})}),"\n",(0,t.jsx)(s.h2,{id:"numbers",children:"Numbers"}),"\n",(0,t.jsxs)(s.p,{children:["R",(0,t.jsx)("sup",{children:"7"}),"RS specification define Numerical Tower, different type of numbers and operation on\nthem. But it's not required for Scheme implementation to add support for them. Some Scheme\nimplementation do support it."]}),"\n",(0,t.jsx)(s.p,{children:"Basic numbers are:"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Integers, e.g. ",(0,t.jsx)(s.code,{children:"10"}),", ",(0,t.jsx)(s.code,{children:"20"}),", or ",(0,t.jsx)(s.code,{children:"1000"})]}),"\n",(0,t.jsxs)(s.li,{children:["Floats, e.g. ",(0,t.jsx)(s.code,{children:"1.2"}),", ",(0,t.jsx)(s.code,{children:"1e-2"})," (you can use ",(0,t.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/Scientific_notation",children:"scientific notation"}),")"]}),"\n",(0,t.jsxs)(s.li,{children:["Rationals e.g. ",(0,t.jsx)(s.code,{children:"1/2"}),", ",(0,t.jsx)(s.code,{children:"3/4"}),", or ",(0,t.jsx)(s.code,{children:"1/10"})]}),"\n",(0,t.jsxs)(s.li,{children:["Complex numbers ",(0,t.jsx)(s.code,{children:"10+10i"}),", ",(0,t.jsx)(s.code,{children:"1/2+1/2i"})]}),"\n"]}),"\n",(0,t.jsxs)(s.p,{children:["There is also a notion of exactness in these numbers. Inexact numbers are floats, the rest of the\nnumbers are exact because they don't give any rounding errors like floats do (this is how\n",(0,t.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/IEEE_754",children:"IEEE 754"})," standard for floating numbers work)."]}),"\n",(0,t.jsxs)(s.p,{children:["There are also special constant ",(0,t.jsx)(s.code,{children:"+nan.0"}),", ",(0,t.jsx)(s.code,{children:"-nan.0"}),", ",(0,t.jsx)(s.code,{children:"+inf.0"}),", and ",(0,t.jsx)(s.code,{children:"-inf.0"}),". Positive and negative\nNot a number object and negative and positive infinity."]}),"\n",(0,t.jsxs)(s.p,{children:["You can convert string to numbers with ",(0,t.jsx)(s.code,{children:"string->number"})," procedure and number to string with ",(0,t.jsx)(s.code,{children:"number->string"}),"."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(string->number "1001" 2)\n;; ==> 9\n(string->number "1001")\n;; ==> 1001\n'})}),"\n",(0,t.jsxs)(s.p,{children:["The first argument is a string and the second one is the base of the number. In similar way you can use\n",(0,t.jsx)(s.code,{children:"number->string"}),":"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(number->string 1001 2)\n;; ==> "1111101001"\n(number->string 1001 16)\n;; ==> "3e9"\n'})}),"\n",(0,t.jsx)(s.h2,{id:"boolean-values",children:"Boolean values"}),"\n",(0,t.jsxs)(s.p,{children:["Scheme define two boolean constants ",(0,t.jsx)(s.code,{children:"#f"})," and ",(0,t.jsx)(s.code,{children:"#t"})," but note that the only false value, according to\nR",(0,t.jsx)("sup",{children:"7"}),"RS specification, should be ",(0,t.jsx)(s.code,{children:"#f"}),". The specification also defines ",(0,t.jsx)(s.code,{children:"#true"})," and ",(0,t.jsx)(s.code,{children:"#false"}),"\naliases. Some Scheme also defines ",(0,t.jsx)(s.code,{children:"true"})," and ",(0,t.jsx)(s.code,{children:"false"})," without hash."]}),"\n",(0,t.jsx)(s.h2,{id:"strings",children:"Strings"}),"\n",(0,t.jsxs)(s.p,{children:["Strings in Scheme use only double quote symbols. They can be multiline. If you want to add double\nquote, you need to escape with the slash ",(0,t.jsx)(s.code,{children:'"this is \\"Scheme\\" language"'}),"."]}),"\n",(0,t.jsxs)(s.p,{children:["You can also inject hex representation of a character with ",(0,t.jsx)(s.code,{children:'"\\x1B;"'})," this will create a string with\nEscape character used by Terminal emulators to add formatting (like colors)."]}),"\n",(0,t.jsx)(s.h2,{id:"characters",children:"Characters"}),"\n",(0,t.jsx)(s.p,{children:"You can define single character as data type"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#\\A\n#\\B\n#\\c\n"})}),"\n",(0,t.jsx)(s.p,{children:"you can use characters to form a string:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(string #\\h #\\e #\\l #\\l #\\o)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["This evaluates into string ",(0,t.jsx)(s.code,{children:'"hello"'})]}),"\n",(0,t.jsx)(s.p,{children:"You can also split the string into individual characters:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(string->vector "hello")\n'})}),"\n",(0,t.jsxs)(s.p,{children:["This evaluates into vector of characters: ",(0,t.jsx)(s.code,{children:"#(#\\h #\\e #\\l #\\l #\\o)"})]}),"\n",(0,t.jsx)(s.h2,{id:"symbols",children:"Symbols"}),"\n",(0,t.jsx)(s.p,{children:"Symbols are special type of objects that are similar to string but without quotes. They can appear as\nvariable names but can also be used as values, but this requires quotation."}),"\n",(0,t.jsx)(s.p,{children:"Valid symbols:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"foo\nbar\nbaz\n"})}),"\n",(0,t.jsx)(s.p,{children:"You can also convert string to symbol with:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(string->symbol "hello")\n'})}),"\n",(0,t.jsxs)(s.p,{children:["Scheme have conversion of using ",(0,t.jsx)(s.code,{children:"->"})," arrow to define procedure that convert types."]}),"\n",(0,t.jsxs)(s.p,{children:["In R",(0,t.jsx)("sup",{children:"7"}),"RS spec there is also a way to define symbols with special characters. Those symbols start and end with a vertical bar character."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(define |foo bar| 10)\n(define |foo () bar| 20)\n(display |foo bar|)\n;; ==> 10\n(display |foo () bar|)\n;; ==> 20\n"})}),"\n",(0,t.jsx)(s.p,{children:"You can also put escaped characters in symbol, like in strings:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(symbol=? '|\\x3BB;| '\u03bb)\n;; ==> #t\n"})}),"\n",(0,t.jsx)(s.h2,{id:"comments",children:"Comments"}),"\n",(0,t.jsx)(s.p,{children:"There are 3 types of comments in Scheme:"}),"\n",(0,t.jsxs)(s.ol,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:";"}),"semicolon create comments to the end of the line"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"#;"})," quote single S-Expression (list/tree or atoms)"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"#| |#"})," those are multiline comments that can wrap any text inside"]}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"empty-list",children:"Empty list"}),"\n",(0,t.jsx)(s.p,{children:"An empty list is a special object in Scheme that indicates end of the list."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"()\n"})}),"\n",(0,t.jsx)(s.h2,{id:"pairs",children:"Pairs"}),"\n",(0,t.jsxs)(s.p,{children:["The base of Lisp and Scheme are pairs also called ",(0,t.jsx)(s.code,{children:"cons"})," cells. You can create them with cons\noperation:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(cons 1 2)\n"})}),"\n",(0,t.jsx)(s.p,{children:"or with dot syntax:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{children:"(1 . 2)\n"})}),"\n",(0,t.jsx)(s.p,{children:"But the second example requires quotation otherwise Scheme will try to evaluate 1 as a function."}),"\n",(0,t.jsx)(s.p,{children:"If cons cells are put into e sequence:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(1 . (2 . (3 . ())))\n"})}),"\n",(0,t.jsx)(s.p,{children:"The last cell is a pair of 3 and empty list. If you create cons like this, it's simplified as a list\nwhen printed:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(1 2 3)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["To create the same list, you can use ",(0,t.jsx)(s.code,{children:"list"})," procedure:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(list 1 2 3)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["To get the first element of the list you use procedure ",(0,t.jsx)(s.code,{children:"car"})," and to get the rest of the list you use\n",(0,t.jsx)(s.code,{children:"cdr"}),". So ",(0,t.jsx)(s.code,{children:"car"})," and ",(0,t.jsx)(s.code,{children:"cdr"})," returns first and second element of the Pair (cons cell)."]}),"\n",(0,t.jsxs)(s.p,{children:["Scheme uses ",(0,t.jsx)(s.code,{children:"car"})," and ",(0,t.jsx)(s.code,{children:"cdr"})," for historical reasons. The first lisp interpreter was using address\nregisters of ",(0,t.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/IBM_704",children:"IBM 704"})," mainframe computer."]}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"car"})," stands for ",(0,t.jsx)(s.strong,{children:"Contents of the Address part of Register"})]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"cdr"})," stands for ",(0,t.jsx)(s.strong,{children:"Contents of the Decrement part of Register"})]}),"\n"]}),"\n",(0,t.jsx)(s.p,{children:"Scheme should also define abbreviations for list accessors:"}),"\n",(0,t.jsxs)(s.p,{children:["Example ",(0,t.jsx)(s.code,{children:"caddr"})," is the third element of the list. It's the same as ",(0,t.jsx)(s.code,{children:"(car (cdr (cdr x)))"}),". Often,\nScheme and lisp interpreters define up to 5 combinations of ",(0,t.jsx)(s.code,{children:"d"})," and ",(0,t.jsx)(s.code,{children:"a"})," to get different elements\nout of a list."]}),"\n",(0,t.jsx)(s.h2,{id:"list-modification",children:"List Modification"}),"\n",(0,t.jsx)(s.p,{children:"You can modify the lists (cons cells) using two functions:"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsx)(s.li,{children:(0,t.jsx)(s.code,{children:"set-car!"})}),"\n",(0,t.jsx)(s.li,{children:(0,t.jsx)(s.code,{children:"set-cdr!"})}),"\n"]}),"\n",(0,t.jsx)(s.p,{children:"By convention, if a procedure modifies something it's indicated with an exclamation mark."}),"\n",(0,t.jsx)(s.h2,{id:"improper-list",children:"Improper list"}),"\n",(0,t.jsx)(s.p,{children:"Proper list is a list with each cdr be a list or empty list at the end:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 4 5)\n"})}),"\n",(0,t.jsx)(s.p,{children:"in the other hand, if you have a list that end with something else then an empty list, you have not\na valid list. This list is often called improper list. It looks like this:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 . 4)\n"})}),"\n",(0,t.jsx)(s.h2,{id:"cycles",children:"Cycles"}),"\n",(0,t.jsx)(s.p,{children:"You can create list cycles directly when defining your data structure with datum syntax."}),"\n",(0,t.jsx)(s.p,{children:"It looks like this:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#0=(1 2 . #0#)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["This will create an infinite list of values ",(0,t.jsx)(s.code,{children:"(1 2 1 2 1 2 ...)"}),". ",(0,t.jsx)(s.code,{children:"#0"})," indicate a pointer and ",(0,t.jsx)(s.code,{children:"#0#"})," a\nreference to the beginning of the list."]}),"\n",(0,t.jsx)(s.h2,{id:"vectors",children:"Vectors"}),"\n",(0,t.jsx)(s.p,{children:"Vectors are created like list, but they have hash in front:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#(1 2 3 4)\n"})}),"\n",(0,t.jsx)(s.p,{children:"This will create an immutable vector that can't be changed. To create a vector that can be modified you\ncan use:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(vector 1 2 3)\n"})}),"\n",(0,t.jsx)(s.h2,{id:"quotations",children:"Quotations"}),"\n",(0,t.jsx)(s.p,{children:"By default if you write lists they are treated as code. To create a data you need quotations."}),"\n",(0,t.jsx)(s.h3,{id:"base-quote",children:"Base Quote"}),"\n",(0,t.jsx)(s.p,{children:"To create basic quotation you use single quote character:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 4)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["When Scheme find this expression it will not try to execute the function ",(0,t.jsx)(s.code,{children:"1"})," only return this list\nas data."]}),"\n",(0,t.jsx)(s.p,{children:"Vector syntax is automatically quoted."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'#(1 2 3)\n"})}),"\n",(0,t.jsx)(s.p,{children:"is the same as:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#(1 2 3)\n"})}),"\n",(0,t.jsx)(s.h3,{id:"quasiquote",children:"Quasiquote"}),"\n",(0,t.jsx)(s.p,{children:"There is also different type of quotation that allow to execute part of the expression. It's called\nquasi quote. To create quasi quote you need back tick symbol. That's why it's often called back\nquotation."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"`(1 2 ,(+ 2 1))\n"})}),"\n",(0,t.jsx)(s.p,{children:"A comma is special syntax that can be used inside quasi quote to indicate that the expression after\nit should be evaluated and inserted into the list. This will evaluate into the same expression as:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["There is also another escape symbol which is ",(0,t.jsx)(s.code,{children:",@"}),". It works similar to a comma, but the data inside (it\nmust be a list) is spliced into the outer list."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"`(1 2 3 ,@(list 4 5 6))\n"})}),"\n",(0,t.jsx)(s.p,{children:"The result expression will look like this:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 4 5 6)\n"})}),"\n",(0,t.jsx)(s.h3,{id:"quotation-of-quotation",children:"Quotation of quotation"}),"\n",(0,t.jsx)(s.p,{children:"If you quote the quotation, you will get a single expression where special symbols are replaced with a list:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"''(1 2 3)\n"})}),"\n",(0,t.jsx)(s.p,{children:"Will return:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-shcheme",children:"(quote (1 2 3))\n"})}),"\n",(0,t.jsx)(s.p,{children:"Because comma is just an alias for quote. You can use them interchangeably. But using symbols is\nfaster to type. If you quote quasi quote expression, you will also get symbols expanded:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'`(1 2 3 ,(+ 1 2) ,@(list 4 5))\n"})}),"\n",(0,t.jsx)(s.p,{children:"This will be the output:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(quasiquote (1 2 3 (unquote (+ 1 2)) (unquote-splicing (list 4 5))))\n"})}),"\n",(0,t.jsx)(s.h3,{id:"quotation-on-vector-literals",children:"Quotation on vector literals"}),"\n",(0,t.jsx)(s.p,{children:"Quasiquote also works with vector literals."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"`#(1 2 ,(+ 1 2))\n;; ==> #(1 2 3)\n`#(1 2 ,@(list 3 4))\n;; ==> #(1 2 3 4)\n"})}),"\n",(0,t.jsx)(s.h2,{id:"special-symbols",children:"Special symbols"}),"\n",(0,t.jsx)(s.p,{children:"Most special symbols in Scheme start with a hash symbol. Example are Byte vectors"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#u8(1 2 3 4)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["Above creates 8 bit byte vector of numbers. In R",(0,t.jsx)("sup",{children:"7"}),"RS, only unsigned 8 bit vectors are\ndefined. But in ",(0,t.jsx)(s.a,{href:"https://srfi.schemers.org/srfi-4/srfi-4.html",children:"SRFI-4"})," are more bit vectors types.\nThey all starts with hash. In different SRFI there are more examples of syntax's that start with\nhash. This is just a convention everything is using."]})]})}function h(e={}){const{wrapper:s}={...(0,c.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,s,n)=>{n.d(s,{R:()=>r,x:()=>a});var i=n(6540);const t={},c=i.createContext(t);function r(e){const s=i.useContext(c);return i.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function a(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),i.createElement(c.Provider,{value:s},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[9263],{2259:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"scheme-intro/data-types","title":"Data Types","description":"All different data types you can have in Scheme","source":"@site/docs/scheme-intro/data-types.md","sourceDirName":"scheme-intro","slug":"/scheme-intro/data-types","permalink":"/docs/scheme-intro/data-types","draft":false,"unlisted":false,"editUrl":"https://github.com/LIPS-scheme/lips/tree/master/docs/docs/scheme-intro/data-types.md","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"description":"All different data types you can have in Scheme"},"sidebar":"tutorialSidebar","previous":{"title":"What is Lisp and Scheme?","permalink":"/docs/scheme-intro/what-is-lisp"},"next":{"title":"Core of Scheme","permalink":"/docs/scheme-intro/core"}}');var t=n(4848),c=n(8453);const r={sidebar_position:2,description:"All different data types you can have in Scheme"},a="Data Types",l={},o=[{value:"Numbers",id:"numbers",level:2},{value:"Boolean values",id:"boolean-values",level:2},{value:"Strings",id:"strings",level:2},{value:"Characters",id:"characters",level:2},{value:"Symbols",id:"symbols",level:2},{value:"Comments",id:"comments",level:2},{value:"Empty list",id:"empty-list",level:2},{value:"Pairs",id:"pairs",level:2},{value:"List Modification",id:"list-modification",level:2},{value:"Improper list",id:"improper-list",level:2},{value:"Cycles",id:"cycles",level:2},{value:"Vectors",id:"vectors",level:2},{value:"Quotations",id:"quotations",level:2},{value:"Base Quote",id:"base-quote",level:3},{value:"Quasiquote",id:"quasiquote",level:3},{value:"Quotation of quotation",id:"quotation-of-quotation",level:3},{value:"Quotation on vector literals",id:"quotation-on-vector-literals",level:3},{value:"Special symbols",id:"special-symbols",level:2}];function d(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,c.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.header,{children:(0,t.jsx)(s.h1,{id:"data-types",children:"Data Types"})}),"\n",(0,t.jsx)(s.h2,{id:"numbers",children:"Numbers"}),"\n",(0,t.jsxs)(s.p,{children:["R",(0,t.jsx)("sup",{children:"7"}),"RS specification define Numerical Tower, different type of numbers and operation on\nthem. But it's not required for Scheme implementation to add support for them. Some Scheme\nimplementation do support it."]}),"\n",(0,t.jsx)(s.p,{children:"Basic numbers are:"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Integers, e.g. ",(0,t.jsx)(s.code,{children:"10"}),", ",(0,t.jsx)(s.code,{children:"20"}),", or ",(0,t.jsx)(s.code,{children:"1000"})]}),"\n",(0,t.jsxs)(s.li,{children:["Floats, e.g. ",(0,t.jsx)(s.code,{children:"1.2"}),", ",(0,t.jsx)(s.code,{children:"1e-2"})," (you can use ",(0,t.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/Scientific_notation",children:"scientific notation"}),")"]}),"\n",(0,t.jsxs)(s.li,{children:["Rationals e.g. ",(0,t.jsx)(s.code,{children:"1/2"}),", ",(0,t.jsx)(s.code,{children:"3/4"}),", or ",(0,t.jsx)(s.code,{children:"1/10"})]}),"\n",(0,t.jsxs)(s.li,{children:["Complex numbers ",(0,t.jsx)(s.code,{children:"10+10i"}),", ",(0,t.jsx)(s.code,{children:"1/2+1/2i"})]}),"\n"]}),"\n",(0,t.jsxs)(s.p,{children:["There is also a notion of exactness in these numbers. Inexact numbers are floats, the rest of the\nnumbers are exact because they don't give any rounding errors like floats do (this is how\n",(0,t.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/IEEE_754",children:"IEEE 754"})," standard for floating numbers work)."]}),"\n",(0,t.jsxs)(s.p,{children:["There are also special constant ",(0,t.jsx)(s.code,{children:"+nan.0"}),", ",(0,t.jsx)(s.code,{children:"-nan.0"}),", ",(0,t.jsx)(s.code,{children:"+inf.0"}),", and ",(0,t.jsx)(s.code,{children:"-inf.0"}),". Positive and negative\nNot a number object and negative and positive infinity."]}),"\n",(0,t.jsxs)(s.p,{children:["You can convert string to numbers with ",(0,t.jsx)(s.code,{children:"string->number"})," procedure and number to string with ",(0,t.jsx)(s.code,{children:"number->string"}),"."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(string->number "1001" 2)\n;; ==> 9\n(string->number "1001")\n;; ==> 1001\n'})}),"\n",(0,t.jsxs)(s.p,{children:["The first argument is a string and the second one is the base of the number. In similar way you can use\n",(0,t.jsx)(s.code,{children:"number->string"}),":"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(number->string 1001 2)\n;; ==> "1111101001"\n(number->string 1001 16)\n;; ==> "3e9"\n'})}),"\n",(0,t.jsx)(s.h2,{id:"boolean-values",children:"Boolean values"}),"\n",(0,t.jsxs)(s.p,{children:["Scheme define two boolean constants ",(0,t.jsx)(s.code,{children:"#f"})," and ",(0,t.jsx)(s.code,{children:"#t"})," but note that the only false value, according to\nR",(0,t.jsx)("sup",{children:"7"}),"RS specification, should be ",(0,t.jsx)(s.code,{children:"#f"}),". The specification also defines ",(0,t.jsx)(s.code,{children:"#true"})," and ",(0,t.jsx)(s.code,{children:"#false"}),"\naliases. Some Scheme also defines ",(0,t.jsx)(s.code,{children:"true"})," and ",(0,t.jsx)(s.code,{children:"false"})," without hash."]}),"\n",(0,t.jsx)(s.h2,{id:"strings",children:"Strings"}),"\n",(0,t.jsxs)(s.p,{children:["Strings in Scheme use only double quote symbols. They can be multiline. If you want to add double\nquote, you need to escape with the slash ",(0,t.jsx)(s.code,{children:'"this is \\"Scheme\\" language"'}),"."]}),"\n",(0,t.jsxs)(s.p,{children:["You can also inject hex representation of a character with ",(0,t.jsx)(s.code,{children:'"\\x1B;"'})," this will create a string with\nEscape character used by Terminal emulators to add formatting (like colors)."]}),"\n",(0,t.jsx)(s.h2,{id:"characters",children:"Characters"}),"\n",(0,t.jsx)(s.p,{children:"You can define single character as data type"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#\\A\n#\\B\n#\\c\n"})}),"\n",(0,t.jsx)(s.p,{children:"you can use characters to form a string:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(string #\\h #\\e #\\l #\\l #\\o)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["This evaluates into string ",(0,t.jsx)(s.code,{children:'"hello"'})]}),"\n",(0,t.jsx)(s.p,{children:"You can also split the string into individual characters:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(string->vector "hello")\n'})}),"\n",(0,t.jsxs)(s.p,{children:["This evaluates into vector of characters: ",(0,t.jsx)(s.code,{children:"#(#\\h #\\e #\\l #\\l #\\o)"})]}),"\n",(0,t.jsx)(s.h2,{id:"symbols",children:"Symbols"}),"\n",(0,t.jsx)(s.p,{children:"Symbols are special type of objects that are similar to string but without quotes. They can appear as\nvariable names but can also be used as values, but this requires quotation."}),"\n",(0,t.jsx)(s.p,{children:"Valid symbols:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"foo\nbar\nbaz\n"})}),"\n",(0,t.jsx)(s.p,{children:"You can also convert string to symbol with:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:'(string->symbol "hello")\n'})}),"\n",(0,t.jsxs)(s.p,{children:["Scheme have conversion of using ",(0,t.jsx)(s.code,{children:"->"})," arrow to define procedure that convert types."]}),"\n",(0,t.jsxs)(s.p,{children:["In R",(0,t.jsx)("sup",{children:"7"}),"RS spec there is also a way to define symbols with special characters. Those symbols start and end with a vertical bar character."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(define |foo bar| 10)\n(define |foo () bar| 20)\n(display |foo bar|)\n;; ==> 10\n(display |foo () bar|)\n;; ==> 20\n"})}),"\n",(0,t.jsx)(s.p,{children:"You can also put escaped characters in symbol, like in strings:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(symbol=? '|\\x3BB;| '\u03bb)\n;; ==> #t\n"})}),"\n",(0,t.jsx)(s.h2,{id:"comments",children:"Comments"}),"\n",(0,t.jsx)(s.p,{children:"There are 3 types of comments in Scheme:"}),"\n",(0,t.jsxs)(s.ol,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:";"}),"semicolon create comments to the end of the line"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"#;"})," quote single S-Expression (list/tree or atoms)"]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"#| |#"})," those are multiline comments that can wrap any text inside"]}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"empty-list",children:"Empty list"}),"\n",(0,t.jsx)(s.p,{children:"An empty list is a special object in Scheme that indicates end of the list."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"()\n"})}),"\n",(0,t.jsx)(s.h2,{id:"pairs",children:"Pairs"}),"\n",(0,t.jsxs)(s.p,{children:["The base of Lisp and Scheme are pairs also called ",(0,t.jsx)(s.code,{children:"cons"})," cells. You can create them with cons\noperation:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(cons 1 2)\n"})}),"\n",(0,t.jsx)(s.p,{children:"or with dot syntax:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{children:"(1 . 2)\n"})}),"\n",(0,t.jsx)(s.p,{children:"But the second example requires quotation otherwise Scheme will try to evaluate 1 as a function."}),"\n",(0,t.jsx)(s.p,{children:"If cons cells are put into e sequence:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(1 . (2 . (3 . ())))\n"})}),"\n",(0,t.jsx)(s.p,{children:"The last cell is a pair of 3 and empty list. If you create cons like this, it's simplified as a list\nwhen printed:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(1 2 3)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["To create the same list, you can use ",(0,t.jsx)(s.code,{children:"list"})," procedure:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(list 1 2 3)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["To get the first element of the list you use procedure ",(0,t.jsx)(s.code,{children:"car"})," and to get the rest of the list you use\n",(0,t.jsx)(s.code,{children:"cdr"}),". So ",(0,t.jsx)(s.code,{children:"car"})," and ",(0,t.jsx)(s.code,{children:"cdr"})," returns first and second element of the Pair (cons cell)."]}),"\n",(0,t.jsxs)(s.p,{children:["Scheme uses ",(0,t.jsx)(s.code,{children:"car"})," and ",(0,t.jsx)(s.code,{children:"cdr"})," for historical reasons. The first lisp interpreter was using address\nregisters of ",(0,t.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/IBM_704",children:"IBM 704"})," mainframe computer."]}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"car"})," stands for ",(0,t.jsx)(s.strong,{children:"Contents of the Address part of Register"})]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"cdr"})," stands for ",(0,t.jsx)(s.strong,{children:"Contents of the Decrement part of Register"})]}),"\n"]}),"\n",(0,t.jsx)(s.p,{children:"Scheme should also define abbreviations for list accessors:"}),"\n",(0,t.jsxs)(s.p,{children:["Example ",(0,t.jsx)(s.code,{children:"caddr"})," is the third element of the list. It's the same as ",(0,t.jsx)(s.code,{children:"(car (cdr (cdr x)))"}),". Often,\nScheme and lisp interpreters define up to 5 combinations of ",(0,t.jsx)(s.code,{children:"d"})," and ",(0,t.jsx)(s.code,{children:"a"})," to get different elements\nout of a list."]}),"\n",(0,t.jsx)(s.h2,{id:"list-modification",children:"List Modification"}),"\n",(0,t.jsx)(s.p,{children:"You can modify the lists (cons cells) using two functions:"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsx)(s.li,{children:(0,t.jsx)(s.code,{children:"set-car!"})}),"\n",(0,t.jsx)(s.li,{children:(0,t.jsx)(s.code,{children:"set-cdr!"})}),"\n"]}),"\n",(0,t.jsx)(s.p,{children:"By convention, if a procedure modifies something it's indicated with an exclamation mark."}),"\n",(0,t.jsx)(s.h2,{id:"improper-list",children:"Improper list"}),"\n",(0,t.jsx)(s.p,{children:"Proper list is a list with each cdr be a list or empty list at the end:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 4 5)\n"})}),"\n",(0,t.jsx)(s.p,{children:"in the other hand, if you have a list that end with something else then an empty list, you have not\na valid list. This list is often called improper list. It looks like this:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 . 4)\n"})}),"\n",(0,t.jsx)(s.h2,{id:"cycles",children:"Cycles"}),"\n",(0,t.jsx)(s.p,{children:"You can create list cycles directly when defining your data structure with datum syntax."}),"\n",(0,t.jsx)(s.p,{children:"It looks like this:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#0=(1 2 . #0#)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["This will create an infinite list of values ",(0,t.jsx)(s.code,{children:"(1 2 1 2 1 2 ...)"}),". ",(0,t.jsx)(s.code,{children:"#0"})," indicate a pointer and ",(0,t.jsx)(s.code,{children:"#0#"})," a\nreference to the beginning of the list."]}),"\n",(0,t.jsx)(s.h2,{id:"vectors",children:"Vectors"}),"\n",(0,t.jsx)(s.p,{children:"Vectors are created like list, but they have hash in front:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#(1 2 3 4)\n"})}),"\n",(0,t.jsx)(s.p,{children:"This will create an immutable vector that can't be changed. To create a vector that can be modified you\ncan use:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(vector 1 2 3)\n"})}),"\n",(0,t.jsx)(s.h2,{id:"quotations",children:"Quotations"}),"\n",(0,t.jsx)(s.p,{children:"By default if you write lists they are treated as code. To create a data you need quotations."}),"\n",(0,t.jsx)(s.h3,{id:"base-quote",children:"Base Quote"}),"\n",(0,t.jsx)(s.p,{children:"To create basic quotation you use single quote character:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 4)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["When Scheme find this expression it will not try to execute the function ",(0,t.jsx)(s.code,{children:"1"})," only return this list\nas data."]}),"\n",(0,t.jsx)(s.p,{children:"Vector syntax is automatically quoted."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'#(1 2 3)\n"})}),"\n",(0,t.jsx)(s.p,{children:"is the same as:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#(1 2 3)\n"})}),"\n",(0,t.jsx)(s.h3,{id:"quasiquote",children:"Quasiquote"}),"\n",(0,t.jsx)(s.p,{children:"There is also different type of quotation that allow to execute part of the expression. It's called\nquasi quote. To create quasi quote you need back tick symbol. That's why it's often called back\nquotation."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"`(1 2 ,(+ 2 1))\n"})}),"\n",(0,t.jsx)(s.p,{children:"A comma is special syntax that can be used inside quasi quote to indicate that the expression after\nit should be evaluated and inserted into the list. This will evaluate into the same expression as:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["There is also another escape symbol which is ",(0,t.jsx)(s.code,{children:",@"}),". It works similar to a comma, but the data inside (it\nmust be a list) is spliced into the outer list."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"`(1 2 3 ,@(list 4 5 6))\n"})}),"\n",(0,t.jsx)(s.p,{children:"The result expression will look like this:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'(1 2 3 4 5 6)\n"})}),"\n",(0,t.jsx)(s.h3,{id:"quotation-of-quotation",children:"Quotation of quotation"}),"\n",(0,t.jsx)(s.p,{children:"If you quote the quotation, you will get a single expression where special symbols are replaced with a list:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"''(1 2 3)\n"})}),"\n",(0,t.jsx)(s.p,{children:"Will return:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-shcheme",children:"(quote (1 2 3))\n"})}),"\n",(0,t.jsxs)(s.p,{children:["Because ",(0,t.jsx)(s.code,{children:"'"})," is just an alias for ",(0,t.jsx)(s.code,{children:"quote"}),". You can use them interchangeably. But using symbols is\nfaster to type. If you quote quasiquote expression, you will also get symbols expanded:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"'`(1 2 3 ,(+ 1 2) ,@(list 4 5))\n"})}),"\n",(0,t.jsx)(s.p,{children:"This will be the output:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"(quasiquote (1 2 3 (unquote (+ 1 2)) (unquote-splicing (list 4 5))))\n"})}),"\n",(0,t.jsx)(s.h3,{id:"quotation-on-vector-literals",children:"Quotation on vector literals"}),"\n",(0,t.jsx)(s.p,{children:"Quasiquote also works with vector literals."}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"`#(1 2 ,(+ 1 2))\n;; ==> #(1 2 3)\n`#(1 2 ,@(list 3 4))\n;; ==> #(1 2 3 4)\n"})}),"\n",(0,t.jsx)(s.h2,{id:"special-symbols",children:"Special symbols"}),"\n",(0,t.jsx)(s.p,{children:"Most special symbols in Scheme start with a hash symbol. Example are Byte vectors"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-scheme",children:"#u8(1 2 3 4)\n"})}),"\n",(0,t.jsxs)(s.p,{children:["Above creates 8 bit byte vector of numbers. In R",(0,t.jsx)("sup",{children:"7"}),"RS, only unsigned 8 bit vectors are\ndefined. But in ",(0,t.jsx)(s.a,{href:"https://srfi.schemers.org/srfi-4/srfi-4.html",children:"SRFI-4"})," there are more bit vectors\ntypes. They all starts with hash. In different SRFI there are more examples of syntax's that start\nwith hash. This is just a convention everything is using."]})]})}function h(e={}){const{wrapper:s}={...(0,c.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,s,n)=>{n.d(s,{R:()=>r,x:()=>a});var i=n(6540);const t={},c=i.createContext(t);function r(e){const s=i.useContext(c);return i.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function a(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),i.createElement(c.Provider,{value:s},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/f724a01c.53807930.js b/assets/js/f724a01c.51b5a57e.js
similarity index 77%
rename from assets/js/f724a01c.53807930.js
rename to assets/js/f724a01c.51b5a57e.js
index 8b4d0303..33c7f954 100644
--- a/assets/js/f724a01c.53807930.js
+++ b/assets/js/f724a01c.51b5a57e.js
@@ -1 +1 @@
-"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[6271],{4758:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>t,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>l});const a=JSON.parse('{"id":"scheme-intro/macros","title":"Macros","description":"Macros are the most powerful feature of Lisp and Scheme","source":"@site/docs/scheme-intro/macros.md","sourceDirName":"scheme-intro","slug":"/scheme-intro/macros","permalink":"/docs/scheme-intro/macros","draft":false,"unlisted":false,"editUrl":"https://github.com/LIPS-scheme/lips/tree/master/docs/docs/scheme-intro/macros.md","tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"sidebar_position":5,"description":"Macros are the most powerful feature of Lisp and Scheme"},"sidebar":"tutorialSidebar","previous":{"title":"Input and Output","permalink":"/docs/scheme-intro/input-output"},"next":{"title":"Streams","permalink":"/docs/scheme-intro/streams"}}');var i=s(4848),r=s(8453);const o={sidebar_position:5,description:"Macros are the most powerful feature of Lisp and Scheme"},t="Macros",c={},l=[{value:"Lisp Macros",id:"lisp-macros",level:2},{value:"Macroexpand",id:"macroexpand",level:3},{value:"New Control Flow Constructs",id:"new-control-flow-constructs",level:3},{value:"Gensyms",id:"gensyms",level:3},{value:"Recursive Macros",id:"recursive-macros",level:3},{value:"Anaphoric Macros",id:"anaphoric-macros",level:3},{value:"Scheme Hygienic Macros",id:"scheme-hygienic-macros",level:2},{value:"Hygiene",id:"hygiene",level:3},{value:"Syntax-rules",id:"syntax-rules",level:3},{value:"Syntax-rules pattern language",id:"syntax-rules-pattern-language",level:3},{value:"Ellipsis",id:"ellipsis",level:3},{value:"Nested Hygienic Macros",id:"nested-hygienic-macros",level:3},{value:"Identifiers",id:"identifiers",level:3},{value:"Recursive Hygienic Macros",id:"recursive-hygienic-macros",level:3},{value:"Anaphoric Hygienic Macros",id:"anaphoric-hygienic-macros",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"macros",children:"Macros"})}),"\n",(0,i.jsxs)(n.p,{children:["Macros are the most powerful feature of the language (both lisp and Scheme). Macros allows you to add\nnew syntax to the language, it also allows making simpler code and reduce\n",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Boilerplate_code",children:"boilerplate"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Macros works like a function, but the arguments of the macro are not evaluated before passing the\nvalue to the function. But instead the code of the arguments are passed to the macro, the macro then\ncan manipulate the code and return new code that is then evaluated. This happens during expansion\ntime before evaluation even happen."}),"\n",(0,i.jsx)(n.h2,{id:"lisp-macros",children:"Lisp Macros"}),"\n",(0,i.jsx)(n.p,{children:"Some scheme implementation supports lisp macros, so I will describe them first."}),"\n",(0,i.jsx)(n.p,{children:"If you have code like this"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (+ 1 2))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["And ",(0,i.jsx)(n.code,{children:"foo"})," is a function, the ",(0,i.jsx)(n.code,{children:"(+ 1 2)"})," will be evaluated and ",(0,i.jsx)(n.code,{children:"3"})," will be passed to the function. But if\n",(0,i.jsx)(n.code,{children:"foo"})," is a macro, the data structure ",(0,i.jsx)(n.code,{children:"(+ 1 2)"})," will be passed to the macro."]}),"\n",(0,i.jsxs)(n.p,{children:["To define a macro, you use usually use ",(0,i.jsx)(n.code,{children:"define-macro"})," syntax. Lisp macros in Scheme are not standard,\nso the syntax may change depending on\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/what-is-lisp#scheme-implementations",children:"Scheme implementation"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (foo expr)\n (case (car expr)\n ((+) (set-car! expr '-))\n ((-) (set-car! expr '+)))\n expr)\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro swap first element of the expression passed as argument. If you pass sum of two numbers\nIt will subtract the values:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (+ 1 2))\n;; ==> -1\n"})}),"\n",(0,i.jsx)(n.p,{children:"if you use minus symbol it will add up the numbers:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (- 1 2))\n;; ==> 3\n"})}),"\n",(0,i.jsx)(n.p,{children:"Instead of modification of existing code you can also create new list:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (foo expr)\n (list (case (car expr) ((+) '-) ((-) '+))\n (cadr expr)\n (caddr expr)))\n"})}),"\n",(0,i.jsx)(n.p,{children:"It will work similarly but only with two numbers:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (- 1 2))\n;; ==> 3\n(foo (+ 1 2))\n;; ==> -1\n"})}),"\n",(0,i.jsx)(n.h3,{id:"macroexpand",children:"Macroexpand"}),"\n",(0,i.jsxs)(n.p,{children:["Some scheme implementation have function ",(0,i.jsx)(n.code,{children:"macroexpand"})," that allow to inspect the result expression\nreturned by the macro."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(macroexpand '(foo (+ 1 2)))\n;; ==> (- 1 2)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Macros can be nested, so one expression can expand into something you don't expect to see. For this\nyou have a function called ",(0,i.jsx)(n.code,{children:"macroexpand-1"})," that should expand macro one time. Which in turn should\nexpand just your macro."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Before you read the next section, it's recommended to read about ",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/data-types#quasiquote",children:"quasiquote syntax"})," first."]})}),"\n",(0,i.jsx)(n.h3,{id:"new-control-flow-constructs",children:"New Control Flow Constructs"}),"\n",(0,i.jsxs)(n.p,{children:["With macros, you can define new control flow (e.g. like ",(0,i.jsx)(n.code,{children:"if"})," statements). Here is an example of\n",(0,i.jsx)(n.code,{children:"when"})," macro that is part of R7RS standard."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-macro (when test . body)\n `(if ,test\n (begin\n ,@body)))\n\n(let ((x 0))\n (when (zero? x)\n (display "x")\n (display " = ")\n (display "zero")\n (newline)))\n;; ==> x = zero\n'})}),"\n",(0,i.jsxs)(n.p,{children:["As you probably already know to use multiple expressions in\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/core#conditionals",children:"if statement"})," you need to use ",(0,i.jsx)(n.code,{children:"begin"}),". The macro use\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/data-types#quasiquote",children:"quasiquote syntax"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You can use ",(0,i.jsx)(n.code,{children:"macroexpand"})," to see what will be the output of the expression:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(macroexpand (let ((x 0))\n (when (zero? x)\n (display "zero")\n (newline))))\n;; ==> (let ((x 0))\n;; ==> (if (zero? x)\n;; ==> (begin\n;; ==> (display "zero")\n;; ==> (newline))))\n'})}),"\n",(0,i.jsx)(n.h3,{id:"gensyms",children:"Gensyms"}),"\n",(0,i.jsx)(n.p,{children:"If you create lisp macros you often may end up with expansion and user code to collide and use the\nsame variables. You call this accidental capture of identifiers."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (when expr body)\n `(let ((tmp ,expr))\n (if tmp\n (begin\n ,@body))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you define macro like this the user of your macro may want to use ",(0,i.jsx)(n.code,{children:"tmp"})," variable and the code\nwill give unexpected behavior:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((tmp 1000))\n (when (> tmp 0)\n (display tmp)\n (newline)))\n;; ==> #t\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will print ",(0,i.jsx)(n.code,{children:"#t"})," but you expect it to print ",(0,i.jsx)(n.code,{children:"1000"}),". This problem can be solved with special kind\nof symbols called ",(0,i.jsx)(n.code,{children:"gensyms"}),". Each gensym is a unique symbol."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (when expr body)\n (let ((tmp (gensym)))\n `(let ((,tmp ,expr))\n (if ,tmp\n (begin\n ,@body)))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Notice that let that call ",(0,i.jsx)(n.code,{children:"gensym"})," is outside quasiquote so it will be evaluated when macro is\nexecuted by the output code will have a unique symbol instead of hard coded symbol ",(0,i.jsx)(n.code,{children:"tmp"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"If you try to evaluate the macro, you will get proper results:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((tmp 1000))\n (when (> tmp 0)\n (display tmp)\n (newline)))\n;; ==> 1000\n"})}),"\n",(0,i.jsx)(n.h3,{id:"recursive-macros",children:"Recursive Macros"}),"\n",(0,i.jsx)(n.p,{children:"You can define recursive macros similarly to recursive function. But you need to make sure that the\nexpansion will stop, similarly to recursive functions you may create infinite loops."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (alist . body)\n (if (null? body)\n ()\n `(cons (cons ,(car body) ,(cadr body)) (alist ,@(cddr body)))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"You can call this macro to create alist based on its arguments:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(alist "foo" 10 "bar" 20 "baz" 30)\n;; ==> (("foo" . 10) ("bar" . 20) ("baz" . 30))\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Note"})," recursive call is inside quote and only argument is unquoted. This is required since\nrecursive macro call needs to appear in the expansion. If you call macro recursively and don't return\nmacro call as output list you will end up in ifninite recursive call."]}),"\n",(0,i.jsx)(n.p,{children:"You can see the macro will expand with macroexpand:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(macroexpand (alist "foo" 10 "bar" 20 "baz" 30))\n;; ==> (cons (cons "foo" 10) (cons (cons "bar" 20) (cons (cons "baz" 30) ())))\n'})}),"\n",(0,i.jsx)(n.h3,{id:"anaphoric-macros",children:"Anaphoric Macros"}),"\n",(0,i.jsx)(n.p,{children:"Anaphoric macros are special kind of macros that leverage the leaking of internal data outside\nthe macro. This is called intentional capture of identifiers. They often expose one or more variable\nthat can be used by the users of the macro."}),"\n",(0,i.jsxs)(n.p,{children:["Example of such macro is ",(0,i.jsx)(n.code,{children:"aif"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (aif test true false)\n `(let ((it ,test))\n (if it\n ,true\n ,false)))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This macro uses ",(0,i.jsx)(n.code,{children:"it"})," variable to hold the testing value that can be used inside user code:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((alist '((a . 10) (b . 20) (c . 30))))\n (aif (assoc 'a alist)\n (begin\n (display (cdr it))\n (newline))))\n;; ==> 10\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you only have one branch like in above code you can define ",(0,i.jsx)(n.code,{children:"awhen"})," macro:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (awhen test . body)\n `(let ((it ,test))\n (if it\n (begin\n ,@body))))\n\n(let ((alist '((a . 10) (b . 20) (c . 30))))\n (awhen (assoc 'a alist)\n (display (cdr it))\n (newline)))\n;; ==> 10\n"})}),"\n",(0,i.jsx)(n.h2,{id:"scheme-hygienic-macros",children:"Scheme Hygienic Macros"}),"\n",(0,i.jsx)(n.p,{children:"The problem with Lisp macros is that they are not hygienic. But what it means?"}),"\n",(0,i.jsx)(n.h3,{id:"hygiene",children:"Hygiene"}),"\n",(0,i.jsxs)(n.p,{children:["If macro is hygienic, it means that it guaranty no leaking of internal code outside of macro. In\nother words guaranteed not to cause the accidental capture of identifiers. Scheme standard define\nnew macro system called ",(0,i.jsx)(n.code,{children:"syntax-rules"})," that is hygienic."]}),"\n",(0,i.jsxs)(n.p,{children:["But we have ",(0,i.jsx)(n.code,{children:"gensym"})," is this not enough to make the macros safe? No"]}),"\n",(0,i.jsxs)(n.p,{children:["Here is an example implementation of ",(0,i.jsx)(n.code,{children:"unless"})," macro that is part of Scheme that fails because it's\nnot hygienic."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (unless test . body)\n `(if (not ,test)\n (begin\n ,@body)))\n"})}),"\n",(0,i.jsx)(n.p,{children:"But in Scheme you can define a variable named not and completely break the macro:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((not (lambda (x) x)))\n (unless #f\n (display "this should not run")\n (newline)))\n;; ==> this should not run\n'})}),"\n",(0,i.jsx)(n.p,{children:"This will print the expression because the unless macro uses not procedure that got overwritten by the\nuser code. Hygiene of macros means that something like this can't happen."}),"\n",(0,i.jsx)(n.h3,{id:"syntax-rules",children:"Syntax-rules"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"syntax-rules"})," in Scheme is different type of macros than lisp macros. It uses a special pattern\nmatching language. Syntax-rules is guarantee by the sec to be hygienic."]}),"\n",(0,i.jsx)(n.p,{children:"Here is the simple definition of a hygienic macro in Scheme:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax unless\n (syntax-rules ()\n ((_ test body ...)\n (if (not test)\n (begin\n body ...)))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro is hygienic. If you use same test as before:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((not (lambda (x) x)))\n (unless #t\n (display "this should not run")\n (newline)))\n'})}),"\n",(0,i.jsx)(n.p,{children:"It will not print any value."}),"\n",(0,i.jsx)(n.h3,{id:"syntax-rules-pattern-language",children:"Syntax-rules pattern language"}),"\n",(0,i.jsx)(n.p,{children:"Syntax rules macro is defined like this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax foo\n (syntax-rules ()\n ((name ) )\n ((name ) )))\n"})}),"\n",(0,i.jsx)(n.p,{children:"The first element if the macro is a list of identifiers that can be used in the pattern."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax for\n (syntax-rules (in)\n ((for element in list body ...)\n (for-each (lambda (element)\n body ...)\n list))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This is an example of a ",(0,i.jsx)(n.code,{children:"for"})," macro that have ",(0,i.jsx)(n.code,{children:"in"})," special keyword inside the parentheses. This\nmacro can be used like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(for i in '(1 2 3 4)\n (display i)\n (newline))\n;; ==> 1\n;; ==> 2\n;; ==> 3\n;; ==> 4\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you try to overwrite the ",(0,i.jsx)(n.code,{children:"in"})," symbol with variable:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((in #t))\n (for i in '(1 2 3 4)\n (display i)\n (newline)))\n;; ==> syntax-rules: no matching syntax in macro\n"})}),"\n",(0,i.jsx)(n.p,{children:"You will get an error because in is no longer a special identifier. It's now a variable."}),"\n",(0,i.jsx)(n.p,{children:"The rest are the list of pattern and expansion. You can build a shape of the code your macro accept\nand use part of the pattern in output macro."}),"\n",(0,i.jsxs)(n.p,{children:["the first element of the pattern is often ",(0,i.jsx)(n.code,{children:"_"})," it matches against the name of the macro."]}),"\n",(0,i.jsx)(n.h3,{id:"ellipsis",children:"Ellipsis"}),"\n",(0,i.jsxs)(n.p,{children:["In lisp macros if you wanted to define a list of any values (including no values) you use\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/data-types#improper-list",children:"improper list"})," (list with dot). In syntax-rules\npattern you use an ellipsis to indicate a list of items. The ellipsis is after the symbol."]}),"\n",(0,i.jsx)(n.p,{children:"Example of usage of ellipsis:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax values\n (syntax-rules ()\n ((_ ((a . b) ...))\n '(a ...))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro use an alist as a pattern and only return the values. Note that it doesn't work on a\nvariable that hold the alist only for alist defined inside the code:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(values ((foo . "lorem") (bar . "ipsum") (baz . "dolor")))\n;; ==> (foo bar baz)\n'})}),"\n",(0,i.jsx)(n.h3,{id:"nested-hygienic-macros",children:"Nested Hygienic Macros"}),"\n",(0,i.jsxs)(n.p,{children:["There are two ways to defined nested macros, macros that define macros. One is escape of ellipsis\nwith ",(0,i.jsx)(n.code,{children:"(... ...)"})," syntax."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax define-for\n (syntax-rules ()\n ((_ symbol)\n (define-syntax symbol\n (syntax-rules ()\n ((_ (var start end) body (... ...))\n (let loop ((var start))\n (if (<= var end)\n (begin\n body (... ...)\n (loop (+ var 1)))))))))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro defines macros that act like for loop, but using tail recursive, named let. You can use this macro like this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-for loop)\n\n(begin\n (loop (i 1 10)\n (display i)\n (if (< i 10)\n (display " ")))\n (newline))\n;; ==> 1 2 3 4 5 6 7 8 9 10\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Another way to define nested marcros is using\n",(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/srfi-46.html",children:"SRFI-46"})," syntax, which allow to change the symbol of ellipsis:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax define-for\n (syntax-rules ()\n ((_ symbol)\n (define-syntax symbol\n (syntax-rules ::: ()\n ((_ (var start end) body :::)\n (let loop ((var start))\n (if (<= var end)\n (begin\n body :::\n (loop (+ var 1)))))))))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"The macro works exactly the same as previous one:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-for loop)\n\n(begin\n (loop (i 1 10)\n (display i)\n (if (< i 10)\n (display " ")))\n (newline))\n;; ==> 1 2 3 4 5 6 7 8 9 10\n'})}),"\n",(0,i.jsx)(n.h3,{id:"identifiers",children:"Identifiers"}),"\n",(0,i.jsx)(n.p,{children:"Inside macros you can add identifiers can can be used like keywords from other programming languages. They match only\nif literal symbol was used and it was not shadowed (overwritten) by variable with same name."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax for\n (syntax-rules (==>)\n ((_ (var start ==> end) body ...)\n (let loop ((var start))\n (if (<= var end)\n (begin\n body ...\n (loop (+ var 1))))))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This for macro define symbol ",(0,i.jsx)(n.code,{children:"==>"})," that can be used as part of the syntax:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((start 1)\n (end 10))\n (for (i start ==> end)\n (display i)\n (if (< i end)\n (display " ")))\n (newline))\n;; ==> 1 2 3 4 5 6 7 8 9 10\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If the symbol ",(0,i.jsx)(n.code,{children:"==>"})," is shadowed by local variable the macro will not match and give an error:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((start 1)\n (end 10)\n (==> "this will not work"))\n (for (i start ==> end)\n (display i)\n (if (< i end)\n (display " ")))\n (newline))\n;; ==> syntax-rules: no matching syntax in macro\n'})}),"\n",(0,i.jsx)(n.p,{children:"special keywords (created with identifiers) can be optional:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax for\n (syntax-rules (==>)\n ((_ (var start end) body ...)\n (_ (var start ==> end) body ...))\n ((_ (var start ==> end) body ...)\n (let loop ((var start))\n (if (<= var end)\n (begin\n body ...\n (loop (+ var 1))))))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This is recursive ",(0,i.jsx)(n.code,{children:"syntax-rules"})," that when using without ",(0,i.jsx)(n.code,{children:"==>"})," symbol it just add it between ",(0,i.jsx)(n.code,{children:"start"}),"\nand ",(0,i.jsx)(n.code,{children:"end"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"recursive-hygienic-macros",children:"Recursive Hygienic Macros"}),"\n",(0,i.jsx)(n.p,{children:"You can define recursive hygienic macros, similar to recursive function you need a base case that will stop expansion and\nrecursve case."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax alist\n (syntax-rules ()\n ((_) ())\n ((_ x y z ...)\n (cons (cons x y) (alist z ...)))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Here is example of recursive macro that expand into series of ",(0,i.jsx)(n.code,{children:"cons"}),". You can use this macro like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(alist 'foo 10 'bar 20 'baz 30)\n;; ==> ((foo . 10) (bar . 20) (baz . 30))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If the Scheme interpreter of choice support macroexpand on hygienic macros you will see that it\nexpact into series of ",(0,i.jsx)(n.code,{children:"cons"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(macroexpand '(alist 'foo 10 'bar 20 'baz 30))\n;; ==> (#:cons (#:cons (quote foo) 10) (#:cons (#:cons (quote bar) 20) (#:cons (#:cons (quote baz) 30) ())))\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output may be different depending on implementation."}),"\n",(0,i.jsx)(n.h3,{id:"anaphoric-hygienic-macros",children:"Anaphoric Hygienic Macros"}),"\n",(0,i.jsxs)(n.p,{children:["By default Scheme ",(0,i.jsx)(n.code,{children:"syntax-rules"})," macros don't allow creating anaphoric macros like lisp macro do.\nBut with ",(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/srfi-139.html",children:"SRFI-139"})," you can implement such macros."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Note"}),": that not every scheme implementation support this ",(0,i.jsx)("abbr",{title:"Scheme Request For\nImplementation",children:"SRFI"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Here is example of ",(0,i.jsx)(n.code,{children:"awhen"})," anaphoric macro that use this ",(0,i.jsx)("abbr",{title:"Scheme Request For\nImplementation",children:"SRFI"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-syntax-parameter it (syntax-rules () ((_) (syntax-error "Use outside aif"))))\n\n(define-syntax awhen\n (syntax-rules ()\n ((_ test body ...)\n (let ((tmp test))\n (syntax-parameterize\n ((it (syntax-rules ()\n ((_) tmp))))\n (if tmp\n (begin\n body ...)))))))\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"syntax-paremetirize"})," works similar to\n",(0,i.jsxs)(n.a,{href:"/docs/scheme-intro/core#dynamic-variables",children:["parameters from R",(0,i.jsx)("sup",{children:"7"}),"RS"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:"You can use this macro like this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((alist \'((foo . "lorem") (bar . "ipsum") (baz . "dolor"))))\n (awhen (assoc \'bar alist)\n (write (cdr (it)))\n (newline)))\n;; ==> "ipsum"\n'})}),"\n",(0,i.jsx)(n.p,{children:"Note the difference, the parameter needs to be wrapped by parentheses like a procedure/macro call."})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>o,x:()=>t});var a=s(6540);const i={},r=a.createContext(i);function o(e){const n=a.useContext(r);return a.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(i):e.components||i:o(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[6271],{4758:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>t,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>l});const a=JSON.parse('{"id":"scheme-intro/macros","title":"Macros","description":"Macros are the most powerful feature of Lisp and Scheme","source":"@site/docs/scheme-intro/macros.md","sourceDirName":"scheme-intro","slug":"/scheme-intro/macros","permalink":"/docs/scheme-intro/macros","draft":false,"unlisted":false,"editUrl":"https://github.com/LIPS-scheme/lips/tree/master/docs/docs/scheme-intro/macros.md","tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"sidebar_position":5,"description":"Macros are the most powerful feature of Lisp and Scheme"},"sidebar":"tutorialSidebar","previous":{"title":"Input and Output","permalink":"/docs/scheme-intro/input-output"},"next":{"title":"Streams","permalink":"/docs/scheme-intro/streams"}}');var i=s(4848),r=s(8453);const o={sidebar_position:5,description:"Macros are the most powerful feature of Lisp and Scheme"},t="Macros",c={},l=[{value:"Lisp Macros",id:"lisp-macros",level:2},{value:"Macroexpand",id:"macroexpand",level:3},{value:"New Control Flow Constructs",id:"new-control-flow-constructs",level:3},{value:"Gensyms",id:"gensyms",level:3},{value:"Recursive Macros",id:"recursive-macros",level:3},{value:"Anaphoric Macros",id:"anaphoric-macros",level:3},{value:"Scheme Hygienic Macros",id:"scheme-hygienic-macros",level:2},{value:"Hygiene",id:"hygiene",level:3},{value:"Syntax-rules",id:"syntax-rules",level:3},{value:"Syntax-rules pattern language",id:"syntax-rules-pattern-language",level:3},{value:"Ellipsis",id:"ellipsis",level:3},{value:"Nested Hygienic Macros",id:"nested-hygienic-macros",level:3},{value:"Identifiers",id:"identifiers",level:3},{value:"Recursive Hygienic Macros",id:"recursive-hygienic-macros",level:3},{value:"Anaphoric Hygienic Macros",id:"anaphoric-hygienic-macros",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"macros",children:"Macros"})}),"\n",(0,i.jsxs)(n.p,{children:["Macros are the most powerful feature of the language (both lisp and Scheme). Macros allows you to add\nnew syntax to the language, it also allows making simpler code and reduce\n",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Boilerplate_code",children:"boilerplate"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Macros works like a function, but the arguments of the macro are not evaluated before passing the\nvalue to the function. But instead the code of the arguments are passed to the macro, the macro then\ncan manipulate the code and return new code that is then evaluated. This happens during expansion\ntime before evaluation even happen."}),"\n",(0,i.jsx)(n.h2,{id:"lisp-macros",children:"Lisp Macros"}),"\n",(0,i.jsx)(n.p,{children:"Some scheme implementation supports lisp macros, so I will describe them first."}),"\n",(0,i.jsx)(n.p,{children:"If you have code like this"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (+ 1 2))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["And ",(0,i.jsx)(n.code,{children:"foo"})," is a function, the ",(0,i.jsx)(n.code,{children:"(+ 1 2)"})," will be evaluated and ",(0,i.jsx)(n.code,{children:"3"})," will be passed to the function. But if\n",(0,i.jsx)(n.code,{children:"foo"})," is a macro, the data structure ",(0,i.jsx)(n.code,{children:"(+ 1 2)"})," will be passed to the macro."]}),"\n",(0,i.jsxs)(n.p,{children:["To define a macro, you use usually use ",(0,i.jsx)(n.code,{children:"define-macro"})," syntax. Lisp macros in Scheme are not standard,\nso the syntax may change depending on\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/what-is-lisp#scheme-implementations",children:"Scheme implementation"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (foo expr)\n (case (car expr)\n ((+) (set-car! expr '-))\n ((-) (set-car! expr '+)))\n expr)\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro swap first element of the expression passed as argument. If you pass sum of two numbers\nIt will subtract the values:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (+ 1 2))\n;; ==> -1\n"})}),"\n",(0,i.jsx)(n.p,{children:"if you use minus symbol it will add up the numbers:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (- 1 2))\n;; ==> 3\n"})}),"\n",(0,i.jsx)(n.p,{children:"Instead of modification of existing code you can also create new list:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (foo expr)\n (list (case (car expr) ((+) '-) ((-) '+))\n (cadr expr)\n (caddr expr)))\n"})}),"\n",(0,i.jsx)(n.p,{children:"It will work similarly but only with two numbers:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(foo (- 1 2))\n;; ==> 3\n(foo (+ 1 2))\n;; ==> -1\n"})}),"\n",(0,i.jsx)(n.h3,{id:"macroexpand",children:"Macroexpand"}),"\n",(0,i.jsxs)(n.p,{children:["Some scheme implementation have function ",(0,i.jsx)(n.code,{children:"macroexpand"})," that allow to inspect the result expression\nreturned by the macro."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(macroexpand '(foo (+ 1 2)))\n;; ==> (- 1 2)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Macros can be nested, so one expression can expand into something you don't expect to see. For this\nyou have a function called ",(0,i.jsx)(n.code,{children:"macroexpand-1"})," that should expand macro one time. Which in turn should\nexpand just your macro."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Before you read the next section, it's recommended to read about ",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/data-types#quasiquote",children:"quasiquote syntax"})," first."]})}),"\n",(0,i.jsx)(n.h3,{id:"new-control-flow-constructs",children:"New Control Flow Constructs"}),"\n",(0,i.jsxs)(n.p,{children:["With macros, you can define new control flow (e.g. like ",(0,i.jsx)(n.code,{children:"if"})," statements). Here is an example of\n",(0,i.jsx)(n.code,{children:"when"})," macro that is part of R7RS standard."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-macro (when test . body)\n `(if ,test\n (begin\n ,@body)))\n\n(let ((x 0))\n (when (zero? x)\n (display "x")\n (display " = ")\n (display "zero")\n (newline)))\n;; ==> x = zero\n'})}),"\n",(0,i.jsxs)(n.p,{children:["As you probably already know to use multiple expressions in\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/core#conditionals",children:"if statement"})," you need to use ",(0,i.jsx)(n.code,{children:"begin"}),". The macro use\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/data-types#quasiquote",children:"quasiquote syntax"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You can use ",(0,i.jsx)(n.code,{children:"macroexpand"})," to see what will be the output of the expression:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(macroexpand (let ((x 0))\n (when (zero? x)\n (display "zero")\n (newline))))\n;; ==> (let ((x 0))\n;; ==> (if (zero? x)\n;; ==> (begin\n;; ==> (display "zero")\n;; ==> (newline))))\n'})}),"\n",(0,i.jsx)(n.h3,{id:"gensyms",children:"Gensyms"}),"\n",(0,i.jsx)(n.p,{children:"If you create lisp macros you often may end up with expansion and user code to collide and use the\nsame variables. You call this accidental capture of identifiers."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (when expr body)\n `(let ((tmp ,expr))\n (if tmp\n (begin\n ,@body))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you define macro like this the user of your macro may want to use ",(0,i.jsx)(n.code,{children:"tmp"})," variable and the code\nwill give unexpected behavior:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((tmp 1000))\n (when (> tmp 0)\n (display tmp)\n (newline)))\n;; ==> #t\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will print ",(0,i.jsx)(n.code,{children:"#t"})," but you expect it to print ",(0,i.jsx)(n.code,{children:"1000"}),". This problem can be solved with special kind\nof symbols called ",(0,i.jsx)(n.code,{children:"gensyms"}),". Each gensym is a unique symbol."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (when expr body)\n (let ((tmp (gensym)))\n `(let ((,tmp ,expr))\n (if ,tmp\n (begin\n ,@body)))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Notice that let that call ",(0,i.jsx)(n.code,{children:"gensym"})," is outside quasiquote so it will be evaluated when macro is\nexecuted by the output code will have a unique symbol instead of hard coded symbol ",(0,i.jsx)(n.code,{children:"tmp"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"If you try to evaluate the macro, you will get proper results:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((tmp 1000))\n (when (> tmp 0)\n (display tmp)\n (newline)))\n;; ==> 1000\n"})}),"\n",(0,i.jsx)(n.h3,{id:"recursive-macros",children:"Recursive Macros"}),"\n",(0,i.jsx)(n.p,{children:"You can define recursive macros similarly to recursive function. But you need to make sure that the\nexpansion will stop, similarly to recursive functions you may create infinite loops."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (alist . body)\n (if (null? body)\n ()\n `(cons (cons ,(car body) ,(cadr body)) (alist ,@(cddr body)))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"You can call this macro to create alist based on its arguments:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(alist "foo" 10 "bar" 20 "baz" 30)\n;; ==> (("foo" . 10) ("bar" . 20) ("baz" . 30))\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Note"})," recursive call is inside quote and only argument is unquoted. This is required since\nrecursive macro call needs to appear in the expansion. If you call macro recursively and don't return\nmacro call as output list you will end up in ifninite recursive call."]}),"\n",(0,i.jsx)(n.p,{children:"You can see the macro will expand with macroexpand:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(macroexpand (alist "foo" 10 "bar" 20 "baz" 30))\n;; ==> (cons (cons "foo" 10) (cons (cons "bar" 20) (cons (cons "baz" 30) ())))\n'})}),"\n",(0,i.jsx)(n.h3,{id:"anaphoric-macros",children:"Anaphoric Macros"}),"\n",(0,i.jsx)(n.p,{children:"Anaphoric macros are special kind of macros that leverage the leaking of internal data outside\nthe macro. This is called intentional capture of identifiers. They often expose one or more variable\nthat can be used by the users of the macro."}),"\n",(0,i.jsxs)(n.p,{children:["Example of such macro is ",(0,i.jsx)(n.code,{children:"aif"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (aif test true false)\n `(let ((it ,test))\n (if it\n ,true\n ,false)))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This macro uses ",(0,i.jsx)(n.code,{children:"it"})," variable to hold the testing value that can be used inside user code:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((alist '((a . 10) (b . 20) (c . 30))))\n (aif (assoc 'a alist)\n (begin\n (display (cdr it))\n (newline))))\n;; ==> 10\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you only have one branch like in above code you can define ",(0,i.jsx)(n.code,{children:"awhen"})," macro:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (awhen test . body)\n `(let ((it ,test))\n (if it\n (begin\n ,@body))))\n\n(let ((alist '((a . 10) (b . 20) (c . 30))))\n (awhen (assoc 'a alist)\n (display (cdr it))\n (newline)))\n;; ==> 10\n"})}),"\n",(0,i.jsx)(n.h2,{id:"scheme-hygienic-macros",children:"Scheme Hygienic Macros"}),"\n",(0,i.jsx)(n.p,{children:"The problem with Lisp macros is that they are not hygienic. But what it means?"}),"\n",(0,i.jsx)(n.h3,{id:"hygiene",children:"Hygiene"}),"\n",(0,i.jsxs)(n.p,{children:["If macro is hygienic, it means that it guaranty no leaking of internal code outside of macro. In\nother words guaranteed not to cause the accidental capture of identifiers. Scheme standard define\nnew macro system called ",(0,i.jsx)(n.code,{children:"syntax-rules"})," that is hygienic."]}),"\n",(0,i.jsxs)(n.p,{children:["But we have ",(0,i.jsx)(n.code,{children:"gensym"})," is this not enough to make the macros safe? No"]}),"\n",(0,i.jsxs)(n.p,{children:["Here is an example implementation of ",(0,i.jsx)(n.code,{children:"unless"})," macro that is part of Scheme that fails because it's\nnot hygienic."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (unless test . body)\n `(if (not ,test)\n (begin\n ,@body)))\n"})}),"\n",(0,i.jsx)(n.p,{children:"But in Scheme you can define a variable named not and completely break the macro:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((not (lambda (x) x)))\n (unless #f\n (display "this should not run")\n (newline)))\n;; ==> this should not run\n'})}),"\n",(0,i.jsx)(n.p,{children:"This will print the expression because the unless macro uses not procedure that got overwritten by the\nuser code. Hygiene of macros means that something like this can't happen."}),"\n",(0,i.jsx)(n.h3,{id:"syntax-rules",children:"Syntax-rules"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"syntax-rules"})," in Scheme is different type of macros than lisp macros. It uses a special pattern\nmatching language. Syntax-rules is guarantee by the sec to be hygienic."]}),"\n",(0,i.jsx)(n.p,{children:"Here is the simple definition of a hygienic macro in Scheme:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax unless\n (syntax-rules ()\n ((_ test body ...)\n (if (not test)\n (begin\n body ...)))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro is hygienic. If you use same test as before:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((not (lambda (x) x)))\n (unless #t\n (display "this should not run")\n (newline)))\n'})}),"\n",(0,i.jsx)(n.p,{children:"It will not print any value."}),"\n",(0,i.jsx)(n.h3,{id:"syntax-rules-pattern-language",children:"Syntax-rules pattern language"}),"\n",(0,i.jsx)(n.p,{children:"Syntax rules macro is defined like this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax foo\n (syntax-rules ()\n ((name ) )\n ((name ) )))\n"})}),"\n",(0,i.jsx)(n.p,{children:"The first element if the macro is a list of identifiers that can be used in the pattern."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax for\n (syntax-rules (in)\n ((for element in list body ...)\n (for-each (lambda (element)\n body ...)\n list))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This is an example of a ",(0,i.jsx)(n.code,{children:"for"})," macro that have ",(0,i.jsx)(n.code,{children:"in"})," special keyword inside the parentheses. This\nmacro can be used like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(for i in '(1 2 3 4)\n (display i)\n (newline))\n;; ==> 1\n;; ==> 2\n;; ==> 3\n;; ==> 4\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you try to overwrite the ",(0,i.jsx)(n.code,{children:"in"})," symbol with variable:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let ((in #t))\n (for i in '(1 2 3 4)\n (display i)\n (newline)))\n;; ==> syntax-rules: no matching syntax in macro\n"})}),"\n",(0,i.jsx)(n.p,{children:"You will get an error because in is no longer a special identifier. It's now a variable."}),"\n",(0,i.jsx)(n.p,{children:"The rest are the list of pattern and expansion. You can build a shape of the code your macro accept\nand use part of the pattern in output macro."}),"\n",(0,i.jsxs)(n.p,{children:["the first element of the pattern is often ",(0,i.jsx)(n.code,{children:"_"})," it matches against the name of the macro."]}),"\n",(0,i.jsx)(n.h3,{id:"ellipsis",children:"Ellipsis"}),"\n",(0,i.jsxs)(n.p,{children:["In lisp macros if you wanted to define a list of any values (including no values) you use\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/data-types#improper-list",children:"improper list"})," (list with dot). In syntax-rules\npattern you use an ellipsis to indicate a list of items. The ellipsis is after the symbol."]}),"\n",(0,i.jsx)(n.p,{children:"Example of usage of ellipsis:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax values\n (syntax-rules ()\n ((_ ((a . b) ...))\n '(a ...))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro use an alist as a pattern and only return the values. Note that it doesn't work on a\nvariable that hold the alist only for alist defined inside the code:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(values ((foo . "lorem") (bar . "ipsum") (baz . "dolor")))\n;; ==> (foo bar baz)\n'})}),"\n",(0,i.jsx)(n.h3,{id:"nested-hygienic-macros",children:"Nested Hygienic Macros"}),"\n",(0,i.jsxs)(n.p,{children:["There are two ways to defined nested macros, macros that define macros. One is escape of ellipsis\nwith ",(0,i.jsx)(n.code,{children:"(... ...)"})," syntax."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax define-for\n (syntax-rules ()\n ((_ symbol)\n (define-syntax symbol\n (syntax-rules ()\n ((_ (var start end) body (... ...))\n (let loop ((var start))\n (if (<= var end)\n (begin\n body (... ...)\n (loop (+ var 1)))))))))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"This macro defines macros that act like for loop, but using tail recursive, named let. You can use this macro like this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-for loop)\n\n(begin\n (loop (i 1 10)\n (display i)\n (if (< i 10)\n (display " ")))\n (newline))\n;; ==> 1 2 3 4 5 6 7 8 9 10\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Another way to define nested marcros is using\n",(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/srfi-46.html",children:"SRFI-46"})," syntax, which allow to change the symbol of ellipsis:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax define-for\n (syntax-rules ()\n ((_ symbol)\n (define-syntax symbol\n (syntax-rules ::: ()\n ((_ (var start end) body :::)\n (let loop ((var start))\n (if (<= var end)\n (begin\n body :::\n (loop (+ var 1)))))))))))\n"})}),"\n",(0,i.jsx)(n.p,{children:"The macro works exactly the same as previous one:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-for loop)\n\n(begin\n (loop (i 1 10)\n (display i)\n (if (< i 10)\n (display " ")))\n (newline))\n;; ==> 1 2 3 4 5 6 7 8 9 10\n'})}),"\n",(0,i.jsx)(n.h3,{id:"identifiers",children:"Identifiers"}),"\n",(0,i.jsx)(n.p,{children:"Inside macros you can add identifiers. They can be used like keywords from other programming languages. They match only\nif literal symbol was used, and it was not shadowed (overwritten) by variable with same name."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax for\n (syntax-rules (==>)\n ((_ (var start ==> end) body ...)\n (let loop ((var start))\n (if (<= var end)\n (begin\n body ...\n (loop (+ var 1))))))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This for macro define symbol ",(0,i.jsx)(n.code,{children:"==>"})," that can be used as part of the syntax:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((start 1)\n (end 10))\n (for (i start ==> end)\n (display i)\n (if (< i end)\n (display " ")))\n (newline))\n;; ==> 1 2 3 4 5 6 7 8 9 10\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If the symbol ",(0,i.jsx)(n.code,{children:"==>"})," is shadowed by local variable the macro will not match and give an error:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((start 1)\n (end 10)\n (==> "this will not work"))\n (for (i start ==> end)\n (display i)\n (if (< i end)\n (display " ")))\n (newline))\n;; ==> syntax-rules: no matching syntax in macro\n'})}),"\n",(0,i.jsx)(n.p,{children:"special keywords (created with identifiers) can be optional:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax for\n (syntax-rules (==>)\n ((_ (var start end) body ...)\n (_ (var start ==> end) body ...))\n ((_ (var start ==> end) body ...)\n (let loop ((var start))\n (if (<= var end)\n (begin\n body ...\n (loop (+ var 1))))))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This is recursive ",(0,i.jsx)(n.code,{children:"syntax-rules"})," that when using without ",(0,i.jsx)(n.code,{children:"==>"})," symbol it just add it between ",(0,i.jsx)(n.code,{children:"start"}),"\nand ",(0,i.jsx)(n.code,{children:"end"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"recursive-hygienic-macros",children:"Recursive Hygienic Macros"}),"\n",(0,i.jsx)(n.p,{children:"You can define recursive hygienic macros, similar to recursive function you need a base case that will stop expansion and\nrecursve case."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-syntax alist\n (syntax-rules ()\n ((_) ())\n ((_ x y z ...)\n (cons (cons x y) (alist z ...)))))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Here is example of recursive macro that expand into series of ",(0,i.jsx)(n.code,{children:"cons"}),". You can use this macro like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(alist 'foo 10 'bar 20 'baz 30)\n;; ==> ((foo . 10) (bar . 20) (baz . 30))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If the Scheme interpreter of choice support macroexpand on hygienic macros you will see that it\nexpact into series of ",(0,i.jsx)(n.code,{children:"cons"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(macroexpand '(alist 'foo 10 'bar 20 'baz 30))\n;; ==> (#:cons (#:cons (quote foo) 10) (#:cons (#:cons (quote bar) 20) (#:cons (#:cons (quote baz) 30) ())))\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output may be different depending on implementation."}),"\n",(0,i.jsx)(n.h3,{id:"anaphoric-hygienic-macros",children:"Anaphoric Hygienic Macros"}),"\n",(0,i.jsxs)(n.p,{children:["By default Scheme ",(0,i.jsx)(n.code,{children:"syntax-rules"})," macros don't allow creating anaphoric macros like lisp macro do.\nBut with ",(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/srfi-139.html",children:"SRFI-139"})," you can implement such macros."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Note"}),": that not every scheme implementation support this ",(0,i.jsx)("abbr",{title:"Scheme Request For\nImplementation",children:"SRFI"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Here is example of ",(0,i.jsx)(n.code,{children:"awhen"})," anaphoric macro that use this ",(0,i.jsx)("abbr",{title:"Scheme Request For\nImplementation",children:"SRFI"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-syntax-parameter it (syntax-rules () ((_) (syntax-error "Use outside aif"))))\n\n(define-syntax awhen\n (syntax-rules ()\n ((_ test body ...)\n (let ((tmp test))\n (syntax-parameterize\n ((it (syntax-rules ()\n ((_) tmp))))\n (if tmp\n (begin\n body ...)))))))\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"syntax-paremetirize"})," works similar to\n",(0,i.jsxs)(n.a,{href:"/docs/scheme-intro/core#dynamic-variables",children:["parameters from R",(0,i.jsx)("sup",{children:"7"}),"RS"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:"You can use this macro like this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(let ((alist \'((foo . "lorem") (bar . "ipsum") (baz . "dolor"))))\n (awhen (assoc \'bar alist)\n (write (cdr (it)))\n (newline)))\n;; ==> "ipsum"\n'})}),"\n",(0,i.jsx)(n.p,{children:"Note the difference, the parameter needs to be wrapped by parentheses like a procedure/macro call."})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>o,x:()=>t});var a=s(6540);const i={},r=a.createContext(i);function o(e){const n=a.useContext(r);return a.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(i):e.components||i:o(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/runtime~main.69492d31.js b/assets/js/runtime~main.49a0b330.js
similarity index 65%
rename from assets/js/runtime~main.69492d31.js
rename to assets/js/runtime~main.49a0b330.js
index 4a3e28b5..9914fa2a 100644
--- a/assets/js/runtime~main.69492d31.js
+++ b/assets/js/runtime~main.49a0b330.js
@@ -1 +1 @@
-(()=>{"use strict";var e,a,t,r,c,f={},b={};function d(e){var a=b[e];if(void 0!==a)return a.exports;var t=b[e]={exports:{}};return f[e].call(t.exports,t,t.exports,d),t.exports}d.m=f,e=[],d.O=(a,t,r,c)=>{if(!t){var f=1/0;for(i=0;i=c)&&Object.keys(d.O).every((e=>d.O[e](t[o])))?t.splice(o--,1):(b=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[t,r,c]},d.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return d.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var c=Object.create(null);d.r(c);var f={};a=a||[null,t({}),t([]),t(t)];for(var b=2&r&&e;"object"==typeof b&&!~a.indexOf(b);b=t(b))Object.getOwnPropertyNames(b).forEach((a=>f[a]=()=>e[a]));return f.default=()=>e,d.d(c,f),c},d.d=(e,a)=>{for(var t in a)d.o(a,t)&&!d.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((a,t)=>(d.f[t](e,a),a)),[])),d.u=e=>"assets/js/"+({360:"b62caabb",478:"840797c7",849:"0058b4c6",1235:"a7456010",1903:"acecf23e",1933:"35ee46b0",2272:"69aa9e93",2301:"6d18ad6b",2711:"9e4087bc",2866:"61d90f5f",3249:"ccc49370",3484:"13a1c259",3789:"726afaaf",3976:"0e384e19",4044:"92fa5ef1",4212:"621db11d",4413:"e511e452",4583:"1df93b7f",4813:"6875c492",5011:"df5a86e1",5742:"aba21aa0",6271:"f724a01c",6365:"c74dcec5",6372:"7e736cac",6440:"3828c8cd",6580:"0522e7aa",6969:"14eb3368",7098:"a7bd4aaa",7209:"f2e31a35",7350:"6878938b",7472:"814f3328",7643:"a6aa9e1f",7915:"c284b67b",8121:"3a2db09e",8130:"f81c1134",8133:"14a48451",8146:"c15d9823",8177:"e1902777",8209:"01a85c17",8401:"17896441",8649:"413466e5",8691:"ab461798",8947:"ef8b811a",9048:"a94703ab",9067:"5ad8d976",9204:"aa178e2b",9263:"d969d8ea",9397:"68243087",9647:"5e95c892",9651:"4f7497d7",9712:"1ba8abbb",9858:"36994c47"}[e]||e)+"."+{195:"8fd6d84d",360:"aa35aa65",416:"39f57a47",478:"c96b5ad6",849:"0f1f0d46",1235:"35651660",1903:"bd6470b3",1933:"8f697f91",2237:"66fcbfbc",2272:"2bf1e156",2301:"27284ffb",2711:"c809fcd6",2866:"91265fd4",3249:"83e04d21",3347:"18dfe3b9",3484:"ce796566",3789:"0a3e15cb",3976:"660f9d11",4044:"d15f09bb",4212:"af8ccb67",4413:"ae4b00d1",4583:"00d19001",4813:"1928affb",5011:"3fa53997",5742:"f5d4ac8d",5929:"afb107d6",6271:"53807930",6365:"c648f275",6372:"1cb4ebab",6440:"6d175597",6580:"d85eb94c",6969:"00347ef4",7098:"8794d1bc",7209:"e4dcaeff",7350:"400083d4",7472:"10db33a4",7643:"a3958393",7915:"3ea8b46c",8121:"c1ec56fd",8130:"ba989b8b",8133:"ddb2c881",8146:"024de278",8158:"848e6959",8177:"a8610025",8209:"5200d571",8401:"42d5ed25",8553:"dfe58b8e",8649:"4bfa6453",8691:"405f8d17",8913:"a77cc8d9",8947:"e6f6be2e",9048:"d90b76ed",9067:"b56915bc",9204:"c464cf32",9263:"b9446a1b",9397:"bd750e75",9647:"4f997d54",9651:"c16406ad",9712:"26884892",9858:"9727f24b"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},c="new-docs:",d.l=(e,a,t,f)=>{if(r[e])r[e].push(a);else{var b,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(s);var c=r[e];if(delete r[e],b.parentNode&&b.parentNode.removeChild(b),c&&c.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=l.bind(null,b.onerror),b.onload=l.bind(null,b.onload),o&&document.head.appendChild(b)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/",d.gca=function(e){return e={17896441:"8401",68243087:"9397",b62caabb:"360","840797c7":"478","0058b4c6":"849",a7456010:"1235",acecf23e:"1903","35ee46b0":"1933","69aa9e93":"2272","6d18ad6b":"2301","9e4087bc":"2711","61d90f5f":"2866",ccc49370:"3249","13a1c259":"3484","726afaaf":"3789","0e384e19":"3976","92fa5ef1":"4044","621db11d":"4212",e511e452:"4413","1df93b7f":"4583","6875c492":"4813",df5a86e1:"5011",aba21aa0:"5742",f724a01c:"6271",c74dcec5:"6365","7e736cac":"6372","3828c8cd":"6440","0522e7aa":"6580","14eb3368":"6969",a7bd4aaa:"7098",f2e31a35:"7209","6878938b":"7350","814f3328":"7472",a6aa9e1f:"7643",c284b67b:"7915","3a2db09e":"8121",f81c1134:"8130","14a48451":"8133",c15d9823:"8146",e1902777:"8177","01a85c17":"8209","413466e5":"8649",ab461798:"8691",ef8b811a:"8947",a94703ab:"9048","5ad8d976":"9067",aa178e2b:"9204",d969d8ea:"9263","5e95c892":"9647","4f7497d7":"9651","1ba8abbb":"9712","36994c47":"9858"}[e]||e,d.p+d.u(e)},(()=>{var e={5354:0,1869:0};d.f.j=(a,t)=>{var r=d.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var c=new Promise(((t,c)=>r=e[a]=[t,c]));t.push(r[2]=c);var f=d.p+d.u(a),b=new Error;d.l(f,(t=>{if(d.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var c=t&&("load"===t.type?"missing":t.type),f=t&&t.target&&t.target.src;b.message="Loading chunk "+a+" failed.\n("+c+": "+f+")",b.name="ChunkLoadError",b.type=c,b.request=f,r[1](b)}}),"chunk-"+a,a)}},d.O.j=a=>0===e[a];var a=(a,t)=>{var r,c,f=t[0],b=t[1],o=t[2],n=0;if(f.some((a=>0!==e[a]))){for(r in b)d.o(b,r)&&(d.m[r]=b[r]);if(o)var i=o(d)}for(a&&a(t);n{"use strict";var e,a,t,c,r,f={},b={};function d(e){var a=b[e];if(void 0!==a)return a.exports;var t=b[e]={exports:{}};return f[e].call(t.exports,t,t.exports,d),t.exports}d.m=f,e=[],d.O=(a,t,c,r)=>{if(!t){var f=1/0;for(i=0;i=r)&&Object.keys(d.O).every((e=>d.O[e](t[o])))?t.splice(o--,1):(b=!1,r0&&e[i-1][2]>r;i--)e[i]=e[i-1];e[i]=[t,c,r]},d.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return d.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.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 r=Object.create(null);d.r(r);var f={};a=a||[null,t({}),t([]),t(t)];for(var b=2&c&&e;"object"==typeof b&&!~a.indexOf(b);b=t(b))Object.getOwnPropertyNames(b).forEach((a=>f[a]=()=>e[a]));return f.default=()=>e,d.d(r,f),r},d.d=(e,a)=>{for(var t in a)d.o(a,t)&&!d.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((a,t)=>(d.f[t](e,a),a)),[])),d.u=e=>"assets/js/"+({360:"b62caabb",478:"840797c7",849:"0058b4c6",1235:"a7456010",1903:"acecf23e",1933:"35ee46b0",2272:"69aa9e93",2301:"6d18ad6b",2711:"9e4087bc",2866:"61d90f5f",3249:"ccc49370",3484:"13a1c259",3789:"726afaaf",3976:"0e384e19",4044:"92fa5ef1",4212:"621db11d",4413:"e511e452",4583:"1df93b7f",4813:"6875c492",5011:"df5a86e1",5742:"aba21aa0",6271:"f724a01c",6365:"c74dcec5",6372:"7e736cac",6440:"3828c8cd",6580:"0522e7aa",6969:"14eb3368",7098:"a7bd4aaa",7209:"f2e31a35",7350:"6878938b",7472:"814f3328",7643:"a6aa9e1f",7915:"c284b67b",8121:"3a2db09e",8130:"f81c1134",8133:"14a48451",8146:"c15d9823",8177:"e1902777",8209:"01a85c17",8401:"17896441",8649:"413466e5",8691:"ab461798",8947:"ef8b811a",9048:"a94703ab",9067:"5ad8d976",9204:"aa178e2b",9263:"d969d8ea",9397:"68243087",9647:"5e95c892",9651:"4f7497d7",9712:"1ba8abbb",9858:"36994c47"}[e]||e)+"."+{195:"8fd6d84d",360:"aa35aa65",416:"39f57a47",478:"c96b5ad6",849:"0f1f0d46",1235:"35651660",1903:"bd6470b3",1933:"8f697f91",2237:"66fcbfbc",2272:"2bf1e156",2301:"27284ffb",2711:"c809fcd6",2866:"91265fd4",3249:"83e04d21",3347:"18dfe3b9",3484:"ce796566",3789:"0a3e15cb",3976:"660f9d11",4044:"d15f09bb",4212:"af8ccb67",4413:"ae4b00d1",4583:"00d19001",4813:"1928affb",5011:"3fa53997",5742:"f5d4ac8d",5929:"afb107d6",6271:"51b5a57e",6365:"c648f275",6372:"1cb4ebab",6440:"6d175597",6580:"9d4051dd",6969:"00347ef4",7098:"8794d1bc",7209:"e4dcaeff",7350:"400083d4",7472:"10db33a4",7643:"a3958393",7915:"3ea8b46c",8121:"c1ec56fd",8130:"ba989b8b",8133:"ddb2c881",8146:"024de278",8158:"848e6959",8177:"a8610025",8209:"5200d571",8401:"42d5ed25",8553:"dfe58b8e",8649:"4bfa6453",8691:"405f8d17",8913:"a77cc8d9",8947:"e6f6be2e",9048:"d90b76ed",9067:"b56915bc",9204:"c464cf32",9263:"47320509",9397:"bd750e75",9647:"4f997d54",9651:"c16406ad",9712:"26884892",9858:"9727f24b"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},r="new-docs:",d.l=(e,a,t,f)=>{if(c[e])c[e].push(a);else{var b,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(s);var r=c[e];if(delete c[e],b.parentNode&&b.parentNode.removeChild(b),r&&r.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=l.bind(null,b.onerror),b.onload=l.bind(null,b.onload),o&&document.head.appendChild(b)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/",d.gca=function(e){return e={17896441:"8401",68243087:"9397",b62caabb:"360","840797c7":"478","0058b4c6":"849",a7456010:"1235",acecf23e:"1903","35ee46b0":"1933","69aa9e93":"2272","6d18ad6b":"2301","9e4087bc":"2711","61d90f5f":"2866",ccc49370:"3249","13a1c259":"3484","726afaaf":"3789","0e384e19":"3976","92fa5ef1":"4044","621db11d":"4212",e511e452:"4413","1df93b7f":"4583","6875c492":"4813",df5a86e1:"5011",aba21aa0:"5742",f724a01c:"6271",c74dcec5:"6365","7e736cac":"6372","3828c8cd":"6440","0522e7aa":"6580","14eb3368":"6969",a7bd4aaa:"7098",f2e31a35:"7209","6878938b":"7350","814f3328":"7472",a6aa9e1f:"7643",c284b67b:"7915","3a2db09e":"8121",f81c1134:"8130","14a48451":"8133",c15d9823:"8146",e1902777:"8177","01a85c17":"8209","413466e5":"8649",ab461798:"8691",ef8b811a:"8947",a94703ab:"9048","5ad8d976":"9067",aa178e2b:"9204",d969d8ea:"9263","5e95c892":"9647","4f7497d7":"9651","1ba8abbb":"9712","36994c47":"9858"}[e]||e,d.p+d.u(e)},(()=>{var e={5354:0,1869:0};d.f.j=(a,t)=>{var c=d.o(e,a)?e[a]:void 0;if(0!==c)if(c)t.push(c[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var r=new Promise(((t,r)=>c=e[a]=[t,r]));t.push(c[2]=r);var f=d.p+d.u(a),b=new Error;d.l(f,(t=>{if(d.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var r=t&&("load"===t.type?"missing":t.type),f=t&&t.target&&t.target.src;b.message="Loading chunk "+a+" failed.\n("+r+": "+f+")",b.name="ChunkLoadError",b.type=r,b.request=f,c[1](b)}}),"chunk-"+a,a)}},d.O.j=a=>0===e[a];var a=(a,t)=>{var c,r,f=t[0],b=t[1],o=t[2],n=0;if(f.some((a=>0!==e[a]))){for(c in b)d.o(b,c)&&(d.m[c]=b[c]);if(o)var i=o(d)}for(a&&a(t);nBlog | LIPS Scheme
-
+
diff --git a/blog/archive.html b/blog/archive.html
index ae3f0518..367feeb4 100644
--- a/blog/archive.html
+++ b/blog/archive.html
@@ -4,7 +4,7 @@
Archive | LIPS Scheme
-
+
diff --git a/blog/authors.html b/blog/authors.html
index 2e7d16a7..5366c438 100644
--- a/blog/authors.html
+++ b/blog/authors.html
@@ -4,7 +4,7 @@
Authors | LIPS Scheme
-
+
diff --git a/blog/emacs-scheme-regex.html b/blog/emacs-scheme-regex.html
index 5b5951e7..89160780 100644
--- a/blog/emacs-scheme-regex.html
+++ b/blog/emacs-scheme-regex.html
@@ -4,7 +4,7 @@
Scheme Regex literals in Emacs | LIPS Scheme
-
+
diff --git a/blog/lips-history.html b/blog/lips-history.html
index 079ad341..dc75b7de 100644
--- a/blog/lips-history.html
+++ b/blog/lips-history.html
@@ -4,7 +4,7 @@
LIPS Scheme History | LIPS Scheme
-
+
diff --git a/blog/tags.html b/blog/tags.html
index 94724370..25ff1365 100644
--- a/blog/tags.html
+++ b/blog/tags.html
@@ -4,7 +4,7 @@
Tags | LIPS Scheme
-
+
diff --git a/blog/tags/emacs.html b/blog/tags/emacs.html
index c0863a02..b30810bf 100644
--- a/blog/tags/emacs.html
+++ b/blog/tags/emacs.html
@@ -4,7 +4,7 @@
One post tagged with "emacs" | LIPS Scheme
-
+
diff --git a/blog/tags/history.html b/blog/tags/history.html
index c47237f7..8b7a3407 100644
--- a/blog/tags/history.html
+++ b/blog/tags/history.html
@@ -4,7 +4,7 @@
One post tagged with "history" | LIPS Scheme
-
+
diff --git a/blog/tags/lips.html b/blog/tags/lips.html
index 33478c3a..8de7354e 100644
--- a/blog/tags/lips.html
+++ b/blog/tags/lips.html
@@ -4,7 +4,7 @@
One post tagged with "lips" | LIPS Scheme
-
+
diff --git a/blog/tags/scheme.html b/blog/tags/scheme.html
index d6a4dd4a..404a369f 100644
--- a/blog/tags/scheme.html
+++ b/blog/tags/scheme.html
@@ -4,7 +4,7 @@
2 posts tagged with "scheme" | LIPS Scheme
-
+
diff --git a/docs/category/introduction-to-scheme.html b/docs/category/introduction-to-scheme.html
index 5cc81bfe..67e0c2a9 100644
--- a/docs/category/introduction-to-scheme.html
+++ b/docs/category/introduction-to-scheme.html
@@ -3,11 +3,11 @@
-Introduction to Scheme | LIPS Scheme
-
+Introduction to Scheme | LIPS Scheme
+
-
Scheme Tutorial, that teaches you basics of Scheme Programming Language. This tutorial explain all the features of Scheme and it's not specific of LIPS Scheme. It mostly describes R7RS standard of Scheme.
Because comma is just an alias for quote. You can use them interchangeably. But using symbols is
-faster to type. If you quote quasi quote expression, you will also get symbols expanded:
+
Because ' is just an alias for quote. You can use them interchangeably. But using symbols is
+faster to type. If you quote quasiquote expression, you will also get symbols expanded:
'`(123 ,(+12),@(list45))
This will be the output:
@@ -214,8 +214,8 @@
Special symb
#u8(1234)
Above creates 8 bit byte vector of numbers. In R7RS, only unsigned 8 bit vectors are
-defined. But in SRFI-4 are more bit vectors types.
-They all starts with hash. In different SRFI there are more examples of syntax's that start with
-hash. This is just a convention everything is using.
+defined. But in SRFI-4 there are more bit vectors
+types. They all starts with hash. In different SRFI there are more examples of syntax's that start
+with hash. This is just a convention everything is using.