From 33e869d5385c7efbc6eb097b2f98613fb3a52bfa Mon Sep 17 00:00:00 2001 From: John Benediktsson Date: Tue, 16 Mar 2021 21:35:26 -0700 Subject: [PATCH] Adding all the talks. --- README.md | 12 + chicago-talk/authors.txt | 1 + chicago-talk/chicago-talk.factor | 53 +++ chicago-talk/deploy.factor | 11 + chicago-talk/summary.txt | 1 + chicago-talk/tags.txt | 1 + galois-talk/authors.txt | 1 + galois-talk/galois-talk.factor | 312 +++++++++++++ galois-talk/summary.txt | 1 + galois-talk/tags.txt | 1 + google-tech-talk/authors.txt | 1 + google-tech-talk/google-tech-talk.factor | 570 +++++++++++++++++++++++ google-tech-talk/summary.txt | 1 + google-tech-talk/tags.txt | 1 + hmc-talk/hmc-talk.factor | 491 +++++++++++++++++++ jvm-summit-talk/authors.txt | 1 + jvm-summit-talk/jvm-summit-talk.factor | 358 ++++++++++++++ jvm-summit-talk/summary.txt | 1 + jvm-summit-talk/tags.txt | 1 + minneapolis-talk/authors.txt | 1 + minneapolis-talk/deploy.factor | 11 + minneapolis-talk/minneapolis-talk.factor | 183 ++++++++ minneapolis-talk/summary.txt | 1 + minneapolis-talk/tags.txt | 1 + otug-talk/2bi.tiff | Bin 0 -> 11744 bytes otug-talk/2bi_at.tiff | Bin 0 -> 13728 bytes otug-talk/2bi_star.tiff | Bin 0 -> 13924 bytes otug-talk/authors.txt | 1 + otug-talk/bi.tiff | Bin 0 -> 8872 bytes otug-talk/bi_at.tiff | Bin 0 -> 8848 bytes otug-talk/bi_star.tiff | Bin 0 -> 9784 bytes otug-talk/otug-talk.factor | 342 ++++++++++++++ otug-talk/summary.txt | 1 + otug-talk/tags.txt | 1 + tc-lisp-talk/authors.txt | 1 + tc-lisp-talk/tags.txt | 1 + tc-lisp-talk/tc-lisp-talk.factor | 535 +++++++++++++++++++++ vpri-talk/authors.txt | 1 + vpri-talk/summary.txt | 1 + vpri-talk/tags.txt | 1 + vpri-talk/vpri-talk.factor | 492 +++++++++++++++++++ 41 files changed, 3393 insertions(+) create mode 100644 README.md create mode 100644 chicago-talk/authors.txt create mode 100644 chicago-talk/chicago-talk.factor create mode 100644 chicago-talk/deploy.factor create mode 100644 chicago-talk/summary.txt create mode 100644 chicago-talk/tags.txt create mode 100644 galois-talk/authors.txt create mode 100644 galois-talk/galois-talk.factor create mode 100644 galois-talk/summary.txt create mode 100644 galois-talk/tags.txt create mode 100644 google-tech-talk/authors.txt create mode 100644 google-tech-talk/google-tech-talk.factor create mode 100644 google-tech-talk/summary.txt create mode 100644 google-tech-talk/tags.txt create mode 100644 hmc-talk/hmc-talk.factor create mode 100644 jvm-summit-talk/authors.txt create mode 100644 jvm-summit-talk/jvm-summit-talk.factor create mode 100644 jvm-summit-talk/summary.txt create mode 100644 jvm-summit-talk/tags.txt create mode 100644 minneapolis-talk/authors.txt create mode 100644 minneapolis-talk/deploy.factor create mode 100644 minneapolis-talk/minneapolis-talk.factor create mode 100644 minneapolis-talk/summary.txt create mode 100644 minneapolis-talk/tags.txt create mode 100644 otug-talk/2bi.tiff create mode 100644 otug-talk/2bi_at.tiff create mode 100644 otug-talk/2bi_star.tiff create mode 100644 otug-talk/authors.txt create mode 100644 otug-talk/bi.tiff create mode 100644 otug-talk/bi_at.tiff create mode 100644 otug-talk/bi_star.tiff create mode 100644 otug-talk/otug-talk.factor create mode 100644 otug-talk/summary.txt create mode 100644 otug-talk/tags.txt create mode 100644 tc-lisp-talk/authors.txt create mode 100644 tc-lisp-talk/tags.txt create mode 100644 tc-lisp-talk/tc-lisp-talk.factor create mode 100644 vpri-talk/authors.txt create mode 100644 vpri-talk/summary.txt create mode 100644 vpri-talk/tags.txt create mode 100644 vpri-talk/vpri-talk.factor diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5aa3e8 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Factor + +The Factor project is maintained and mirrored at +[https://github.com/factor/factor](https://github.com/factor/factor) + +## Talks and Presentations + +Various talks and presentations that have been given are included here as +runnable vocabularies. + +If you'd like to run these, you can add this directory as a ``vocab-root`` +and then ``"name-of-the-talk-to-launch" run``. diff --git a/chicago-talk/authors.txt b/chicago-talk/authors.txt new file mode 100644 index 0000000..1901f27 --- /dev/null +++ b/chicago-talk/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/chicago-talk/chicago-talk.factor b/chicago-talk/chicago-talk.factor new file mode 100644 index 0000000..02ddc42 --- /dev/null +++ b/chicago-talk/chicago-talk.factor @@ -0,0 +1,53 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: slides help.markup ; +IN: talks.chicago-talk + +CONSTANT: chicago-slides +{ + { $slide "factor" + { $url "http://factorcode.org" } + } + { $slide "goals" + "high level language" + "expressive and extensible" + "reasonable performance" + "interactive development with arbitrary redefinition" + "standalone app deployment (strip out compiler and REPL)" + } + { $slide "challenges" + + "higher-order functions" + "dynamic typing" + "memory allocation" + "float boxing/unboxing" + "integer overflow checks" + "user-defined abstractions" + } + { $slide "implementation" + "VM: 12 kloc of C, library: >100 kloc of Factor" + "generational copying garbage collection, card marking write barrier" + "full continuations, tail calls" + "simple non-optimizing “bootstrap” compiler" + "optimizing compiler" + } + { $slide "optimizing compiler" + "about 12,000 lines of Factor code" + "targets x86-32, x86-64, PowerPC" + "factor code ⇒ high-level SSA ⇒ low-level SSA ⇒ machine code" + } + { $slide "high-level optimizer" + "macro expansion, defunctionalization" + "type and interval inference, sparse conditional constant propagation, method inlining" + "escape analysis and tuple unboxing" + } + { $slide "low-level optimizer" + "alias analysis, value numbering, write barrier elimination" + "linear scan register allocation" + } +} + +: chicago-talk ( -- ) + chicago-slides "Chicago talk" slides-window ; + +MAIN: chicago-talk diff --git a/chicago-talk/deploy.factor b/chicago-talk/deploy.factor new file mode 100644 index 0000000..ce8739e --- /dev/null +++ b/chicago-talk/deploy.factor @@ -0,0 +1,11 @@ +USING: tools.deploy.config ; +V{ + { deploy-ui? t } + { deploy-io 3 } + { deploy-reflection 1 } + { deploy-math? t } + { deploy-word-props? f } + { deploy-c-types? f } + { "stop-after-last-window?" t } + { deploy-name "Chicago Talk" } +} diff --git a/chicago-talk/summary.txt b/chicago-talk/summary.txt new file mode 100644 index 0000000..229e1a3 --- /dev/null +++ b/chicago-talk/summary.txt @@ -0,0 +1 @@ +Slides for a talk at the Pycon VM Summit, Chicago, IL, March 2009 diff --git a/chicago-talk/tags.txt b/chicago-talk/tags.txt new file mode 100644 index 0000000..8ee64cd --- /dev/null +++ b/chicago-talk/tags.txt @@ -0,0 +1 @@ +talks diff --git a/galois-talk/authors.txt b/galois-talk/authors.txt new file mode 100644 index 0000000..1901f27 --- /dev/null +++ b/galois-talk/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/galois-talk/galois-talk.factor b/galois-talk/galois-talk.factor new file mode 100644 index 0000000..87e7914 --- /dev/null +++ b/galois-talk/galois-talk.factor @@ -0,0 +1,312 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: slides help.markup math arrays hashtables namespaces +sequences kernel parser memoize io.encodings.binary +locals kernel.private help.vocabs assocs quotations +urls peg.ebnf tools.annotations tools.crossref +help.topics math.functions compiler.tree.optimizer +compiler.cfg.optimizer fry ; +IN: talks.galois-talk + +CONSTANT: galois-slides +{ + { $slide "Factor!" + { $url "http://factorcode.org" } + "Development started in 2003" + "Open source (BSD license)" + "Influenced by Forth, Lisp, and Smalltalk" + "Blurs the line between language and library" + "Interactive development" + } + { $slide "Words and the stack" + "Stack based, dynamically typed" + { $code "{ 1 1 3 4 4 8 9 9 } dup duplicates diff ." } + "Words: named code snippets" + { $code ": remove-duplicates ( seq -- seq' )" " dup duplicates diff ;" } + { $code "{ 1 1 3 4 4 8 9 9 } remove-duplicates ." } + } + { $slide "Vocabularies" + "Vocabularies: named sets of words" + { $link "vocab-index" } + { { $link POSTPONE: USING: } " loads dependencies" } + "Source, docs, tests in one place" + } + { $slide "Interactive development" + "Programming is hard, let's play tetris" + { $vocab-link "tetris" } + "Tetris is hard too... let's cheat" + "Factor workflow: change code, F2, test, repeat" + } + { $slide "Quotations" + "Quotation: unnamed block of code" + "Combinators: words taking quotations" + { $code "10 dup 0 < [ 1 - ] [ 1 + ] if ." } + { $code "{ -1 1 -2 0 3 } [ 0 max ] map ." } + "Partial application:" + { $code ": clamp ( seq n -- seq' ) '[ _ max ] map ;" "{ -1 1 -2 0 3 } 0 clamp" } + } + { $slide "Object system" + "CLOS with single dispatch" + "A tuple is a user-defined class which holds named values." + { $code + "TUPLE: rectangle width height ;" + "TUPLE: circle radius ;" + } + } + { $slide "Object system" + "Constructing instances:" + { $code "rectangle new" } + { $code "rectangle boa" } + "Let's encapsulate:" + { $code + ": ( w h -- r ) rectangle boa ;" + ": ( r -- c ) circle boa ;" + } + } + { $slide "Object system" + "Generic words and methods" + { $code "GENERIC: area ( shape -- n )" } + "Two methods:" + { $code + "USE: math.constants" + "" + "M: rectangle area" + " [ width>> ] [ height>> ] bi * ;" + "" + "M: circle area radius>> sq pi * ;" + } + } + { $slide "Object system" + "We can compute areas now." + { $code "100 20 area ." } + { $code "3 area ." } + } + { $slide "Object system" + "Object system handles dynamic redefinition very well" + { $code "TUPLE: person name age occupation ;" } + "Make an instance..." + } + { $slide "Object system" + "Let's add a new slot:" + { $code "TUPLE: person name age address occupation ;" } + "Fill it in with inspector..." + "Change the order:" + { $code "TUPLE: person name occupation address ;" } + } + { $slide "Object system" + "How does it work?" + "Objects are not hashtables; slot access is very fast" + "Redefinition walks the heap; expensive but rare" + } + { $slide "Object system" + "Supports \"duck typing\"" + "Two tuples can have a slot with the same name" + "Code that uses accessors will work on both" + "Accessors are auto-generated generic words" + } + { $slide "Object system" + "Predicate classes" + { $code + "PREDICATE: positive < integer 0 > ;" + "PREDICATE: negative < integer 0 < ;" + "" + "GENERIC: abs ( n -- )" + "" + "M: positive abs ;" + "M: negative abs -1 * ;" + "M: integer abs ;" + } + } + { $slide "Object system" + "More: inheritance, type declarations, read-only slots, union, intersection, singleton classes, reflection" + "Object system is entirely implemented in Factor" + } + { $slide "The parser" + "All data types have a literal syntax" + "Literal hashtables and arrays are very useful in data-driven code" + "\"Code is data\" because quotations are objects (enables Lisp-style macros)" + { $code "H{ { \"cookies\" 12 } { \"milk\" 10 } }" } + "Libraries can define new parsing words" + } + { $slide "Example: regexp" + { $vocab-link "regexp" } + "Pre-compiles regexp at parse time" + "Implemented with library code" + { $code "USE: regexp" } + { $code "\"ababbc\" \"[ab]+c\" matches? ." } + { $code "\"ababbc\" R/ [ab]+c/ matches? ." } + } + { $slide "Example: memoization" + { "Memoization with " { $link POSTPONE: MEMO: } } + { $code + ": fib ( m -- n )" + " dup 1 > [" + " [ 1 - fib ] [ 2 - fib ] bi +" + " ] when ;" + } + "Very slow! Let's profile it..." + } + { $slide "Example: memoization" + { "Let's use " { $link POSTPONE: MEMO: } " instead of " { $link POSTPONE: : } } + { $code + "MEMO: fib ( m -- n )" + " dup 1 > [" + " [ 1 - fib ] [ 2 - fib ] bi +" + " ] when ;" + } + "Much faster" + } + { $slide "Meta-circularity" + { { $link POSTPONE: MEMO: } " is just a library word" } + { "But so is " { $link POSTPONE: : } } + "Factor's parser is written in Factor" + { "All syntax is just parsing words: " { $link POSTPONE: [ } ", " { $link POSTPONE: " } } + } + { $slide "Extensible syntax, DSLs" + "Most parsing words fall in one of two categories" + "First category: literal syntax for new data types" + "Second category: defining new types of words" + "Some parsing words are more complicated" + } + { $slide "Example: printf" + { { $link POSTPONE: EBNF: } ": a complex parsing word" } + "Implements a custom syntax for expressing parsers: like OMeta!" + { "Example: " { $vocab-link "printf-example" } } + { $code "\"cheese\" \"vegan\" \"%s is not %s\\n\" printf" } + { $code "\"Factor\" 5 \"%s is %d years old\\n\" printf" } + } + { $slide "Example: simple web browser" + { $vocab-link "webkit-demo" } + "Demonstrates Cocoa binding" + "Let's deploy a stand-alone binary with the deploy tool" + "Deploy tool generates binaries with no external dependencies" + } + { $slide "Locals and lexical scope" + "Sometimes, there's no good stack solution to a problem" + "Or, you're porting existing code in a quick-and-dirty way" + "Our solution: implement named locals as a DSL in Factor" + "Influenced by Scheme and Lisp" + } + { $slide "Locals and lexical scope" + { "Define lambda words with " { $link POSTPONE: :: } } + { "Establish bindings with " { $link POSTPONE: [let } " and " { $snippet "[let*" } } + "Mutable bindings with correct semantics" + { "Named inputs for quotations with " { $link POSTPONE: [| } } + "Full closures" + } + { $slide "Locals and lexical scope" + "Combinator with 5 parameters!" + { $code + ":: branch ( a b neg zero pos -- )" + " a b = zero [ a b < neg pos if ] if ; inline" + } + "Unwieldy with the stack" + } + { $slide "Locals and lexical scope" + { $code + ": check-drinking-age ( age -- )" + " 21" + " [ \"You're underage!\" print ]" + " [ \"Grats, you're now legal\" print ]" + " [ \"Go get hammered\" print ]" + " branch ;" + } + } + { $slide "Locals and lexical scope" + "Locals are entirely implemented in Factor" + "Example of compile-time meta-programming" + "No performance penalty -vs- using the stack" + "In the base image, only 59 words out of 13,000 use locals" + } + { $slide "More about partial application" + { { $link POSTPONE: '[ } " is \"fry syntax\"" } + { $code "'[ _ + ] == [ + ] curry" } + { $code "'[ @ t ] == [ t ] compose" } + { $code "'[ _ nth @ ] == [ [ nth ] curry ] dip compose" } + { $code "'[ [ _ ] dip nth ] == [ [ ] curry dip nth ] curry" } + { "Fry and locals desugar to " { $link curry } ", " { $link compose } } + } + { $slide "Help system" + "Help markup is just literal data" + { "Look at the help for " { $link T{ link f + } } } + "These slides are built with the help system and a custom style sheet" + { $vocab-link "talks.galois-talk" } + } + { $slide "Why stack-based?" + "Because nobody else is doing it" + "Interesting properties: concatenation is composition, chaining functions together, \"fluent\" interfaces, new combinators" + { $vocab-link "smtp-example" } + { $code + "{ \"chicken\" \"beef\" \"pork\" \"turkey\" }" + "[ 5 short head ] map ." + } + } + { $slide "Implementation" + "VM: garbage collection, bignums, ..." + "Bootstrap image: parser, hashtables, object system, ..." + "Non-optimizing compiler" + "Stage 2 bootstrap: optimizing compiler, UI, ..." + "Full image contains machine code" + } + { $slide "Compiler" + { "Let's look at " { $vocab-link "benchmark.mandel" } } + "A naive implementation would be very slow" + "Combinators, partial application" + "Boxed complex numbers" + "Boxed floats" + { "Redundancy in " { $link absq } " and " { $link sq } } + } + { $slide "Compiler: high-level optimizer" + "High-level SSA IR" + "Type inference (classes, intervals, arrays with a fixed length, literals, ...)" + "Escape analysis and tuple unboxing" + } + { $slide "Compiler: high-level optimizer" + "Loop index becomes a fixnum, complex numbers unboxed, generic arithmetic inlined, higher-order code become first-order..." + { $code "[ c pixel ] optimized." } + } + { $slide "Compiler: low-level optimizer" + "Low-level SSA IR" + "Alias analysis" + "Value numbering" + "Linear scan register allocation" + } + { $slide "Compiler: low-level optimizer" + "Redundant stack operations eliminated, intermediate floats unboxed..." + { $code "[ c pixel ] regs." } + } + { $slide "Garbage collection" + "All roots are identified precisely" + "Generational copying for data" + "Mark sweep for native code" + } + { $slide "Project infrastructure" + { $url "http://factorcode.org" } + { $url "http://concatenative.org" } + { $url "http://docs.factorcode.org" } + { $url "http://planet.factorcode.org" } + "Uses our HTTP server, SSL, DB, Atom libraries..." + } + { $slide "Project infrastructure" + "Build farm, written in Factor" + "12 platforms" + "Builds Factor and all libraries, runs tests, makes binaries" + "Saves us from the burden of making releases by hand" + "Maintains stability" + } + { $slide "Community" + "#concatenative irc.freenode.net: 50-60 members" + "factor-talk@lists.sf.net: 180 subscribers" + "About 30 people have code in the Factor repository" + "Easy to get started: binaries, lots of docs, friendly community..." + } + { $slide "That's all, folks" + "It is hard to cover everything in a single talk" + "Factor has many cool things that I didn't talk about" + "Questions?" + } +} + +: galois-talk ( -- ) galois-slides "Galois talk" slides-window ; + +MAIN: galois-talk diff --git a/galois-talk/summary.txt b/galois-talk/summary.txt new file mode 100644 index 0000000..00f30ac --- /dev/null +++ b/galois-talk/summary.txt @@ -0,0 +1 @@ +Slides from a talk at Galois by Slava Pestov, October 2008 diff --git a/galois-talk/tags.txt b/galois-talk/tags.txt new file mode 100644 index 0000000..8ee64cd --- /dev/null +++ b/galois-talk/tags.txt @@ -0,0 +1 @@ +talks diff --git a/google-tech-talk/authors.txt b/google-tech-talk/authors.txt new file mode 100644 index 0000000..1901f27 --- /dev/null +++ b/google-tech-talk/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/google-tech-talk/google-tech-talk.factor b/google-tech-talk/google-tech-talk.factor new file mode 100644 index 0000000..a0b511f --- /dev/null +++ b/google-tech-talk/google-tech-talk.factor @@ -0,0 +1,570 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: slides help.markup math arrays hashtables namespaces +kernel sequences parser memoize io.encodings.binary +locals kernel.private help.vocabs assocs quotations +urls peg.ebnf tools.annotations tools.crossref +help.topics math.functions compiler.tree.optimizer +compiler.cfg.optimizer fry ; +IN: talks.google-tech-talk + +CONSTANT: google-slides +{ + { $slide "Factor!" + { $url "http://factorcode.org" } + "Development started in 2003" + "Open source (BSD license)" + "First result for \"Factor\" on Google :-)" + "Influenced by Forth, Lisp, and Smalltalk (but don't worry if you don't know them)" + } + { $slide "Language overview" + "Words operate on a stack" + "Functional" + "Object-oriented" + "Rich collections library" + "Rich input/output library" + "Optional named local variables" + "Extensible syntax" + } + { $slide "Example: factorial" + "Lame example, but..." + { $code "USE: math.ranges" ": factorial ( n -- n! )" " 1 [a,b] product ;" } + { $code "100 factorial ." } + } + { $slide "Example: sending an e-mail" + { $vocab-link "smtp-example" } + "Demonstrates basic stack syntax and tuple slot setters" + } + { $slide "Functional programming" + "Code is data in Factor" + { { $snippet "[ ... ]" } " is a block of code pushed on the stack" } + { "We call them " { $emphasis "quotations" } } + { "Words which take quotations as input are called " { $emphasis "combinators" } } + } + { $slide "Functional programming" + { $code "10 dup 0 < [ 1 - ] [ 1 + ] if ." } + { $code "10 [ \"Hello Googlers!\" print ] times" } + { $code + "USING: io.encodings.ascii unicode ;" + "{ \"tomato\" \"orange\" \"banana\" }" + "\"out.txt\" ascii [" + " [ >upper print ] each" + "] with-file-writer" + } + } + { $slide "Object system: motivation" + "Encapsulation, polymorphism, inheritance" + "Smalltalk, Python, Java approach: methods inside classes" + "Often the \"message sending\" metaphor is used to describe such systems" + } + { $slide "Object system: motivation" + { $code + "class Rect {" + " int x, y;" + " int area() { ... }" + " int perimeter() { ... }" + "}" + "" + "class Circle {" + " int radius;" + " int area() { ... }" + " int perimeter() { ... }" + "}" + } + } + { $slide "Object system: motivation" + "Classical functional language approach: functions switch on a type" + { $code + "data Shape = Rect w h | Circle r" + "" + "area s = s of" + " (Rect w h) = ..." + "| (Circle r) = ..." + "" + "perimeter s = s of" + " (Rect w h) = ..." + "| (Circle r) = ..." + } + } + { $slide "Object system: motivation" + "First approach: hard to extend existing types with new operations (open classes, etc are a hack)" + "Second approach: hard to extend existing operations with new types" + "Common Lisp Object System (CLOS): decouples classes from methods." + "Factor's object system is a simplified CLOS" + } + { $slide "Object system" + "A tuple is a user-defined class which holds named values." + { $code + "TUPLE: rectangle width height ;" + "TUPLE: circle radius ;" + } + } + { $slide "Object system" + "Constructing instances:" + { $code "rectangle new" } + { $code "rectangle boa" } + "Let's encapsulate:" + { $code + ": ( w h -- r ) rectangle boa ;" + ": ( r -- c ) circle boa ;" + } + } + { $slide "Object system" + "Generic words and methods" + { $code "GENERIC: area ( shape -- n )" } + "Two methods:" + { $code + "USE: math.constants" + "" + "M: rectangle area" + " [ width>> ] [ height>> ] bi * ;" + "" + "M: circle area radius>> sq pi * ;" + } + } + { $slide "Object system" + "We can compute areas now." + { $code "100 20 area ." } + { $code "3 area ." } + } + { $slide "Object system" + "New operation, existing types:" + { $code + "GENERIC: perimeter ( shape -- n )" + "" + "M: rectangle perimeter" + " [ width>> ] [ height>> ] bi + 2 * ;" + "" + "M: circle perimeter" + " radius>> 2 * pi * ;" + } + } + { $slide "Object system" + "We can compute perimeters now." + { $code "100 20 perimeter ." } + { $code "3 perimeter ." } + } + { $slide "Object system" + "New type, extending existing operations:" + { $code + "TUPLE: triangle base height ;" + "" + ": ( b h -- t ) triangle boa ;" + "" + "M: triangle area" + " [ base>> ] [ height>> ] bi * 2 / ;" + } + } + { $slide "Object system" + "New type, extending existing operations:" + { $code + ": hypotenuse ( x y -- z ) [ sq ] bi@ + sqrt ;" + "" + "M: triangle perimeter" + " [ base>> ] [ height>> ] bi" + " [ + ] [ hypotenuse ] 2bi + ;" + } + } + { $slide "Object system" + "We can ask an object if its a rectangle:" + { $code "70 65 rectangle? ." } + { $code "13 rectangle? ." } + { "How do we tell if something is a " { $emphasis "shape" } "?" } + } + { $slide "Object system" + "We define a mixin class for shapes, and add our existing data types as instances:" + { $code + "MIXIN: shape" + "INSTANCE: rectangle shape" + "INSTANCE: circle shape" + "INSTANCE: triangle shape" + } + } + { $slide "Object system" + "Now, we can ask objects if they are shapes or not:" + { $code "13 shape? ." } + { $code "3.14 shape? ." } + } + { $slide "Object system" + "Or put methods on shapes:" + { $code + "GENERIC: tell-me ( obj -- )" + "" + "M: shape tell-me" + " \"My area is \" write area . ;" + "" + "M: integer tell-me" + " \"I am \" write" + " even? \"even\" \"odd\" ? print ;" + } + } + { $slide "Object system" + "Let's test our new generic word:" + { $code "13 tell-me" } + { $code "103 76 tell-me" } + { $code "101 tell-me" } + { { $link integer } ", " { $link array } ", and others are built-in classes" } + } + { $slide "Object system" + "Anyone can define new shapes..." + { $code + "TUPLE: parallelogram ... ;" + "" + "INSTANCE: parallelogram shape" + "" + "M: parallelogram area ... ;" + "" + "M: parallelogram perimeter ... ;" + } + } + { $slide "Object system" + "More: inheritance, type declarations, read-only slots, predicate, intersection, singleton classes, reflection" + "Object system is entirely implemented in Factor: 2184 lines" + { { $vocab-link "generic" } ", " { $vocab-link "classes" } ", " { $vocab-link "slots" } } + } + { $slide "Collections" + "Sequences (arrays, vector, strings, ...)" + "Associative mappings (hashtables, ...)" + { "More: deques, heaps, purely functional structures, disjoint sets, and more: " + { $link T{ vocab-tag f "collections" } } } + } + { $slide "Sequences" + { "Protocol: " { $link length } ", " { $link set-length } ", " { $link nth } ", " { $link set-nth } } + { "Combinators: " { $link each } ", " { $link map } ", " { $link filter } ", " { $link produce } ", and more: " { $link "sequences-combinators" } } + { "Utilities: " { $link append } ", " { $link reverse } ", " { $link first } ", " { $link second } ", ..." } + } + { $slide "Example: bin packing" + { "We have " { $emphasis "m" } " objects and " { $emphasis "n" } " bins, and we want to distribute these objects as evenly as possible." } + { $vocab-link "distribute-example" } + "Demonstrates various sequence utilities and vector words" + { $code "20 13 distribute ." } + } + { $slide "Unicode strings" + "Strings are sequences of 21-bit Unicode code points" + "Efficient implementation: ASCII byte string unless it has chars > 127" + "If a byte char has high bit set, the remaining 14 bits come from auxiliary vector" + } + { $slide "Unicode strings" + "Unicode-aware case conversion, char classes, collation, word breaks, and so on..." + { $code "USE: unicode" "\"ß\" >upper ." } + } + { $slide "Unicode strings" + "All external byte I/O is encoded/decoded" + "ASCII, UTF8, UTF16, EBCDIC..." + { $code "USE: io.encodings.utf8" "\"document.txt\" utf8" "[ readln ] with-file-reader" } + { "Binary I/O is supported as well with the " { $link binary } " encoding" } + } + { $slide "Associative mappings" + { "Protocol: " { $link assoc-size } ", " { $link at* } ", " { $link set-at } ", " { $link delete-at } } + { "Combinators: " { $link assoc-each } ", " { $link assoc-map } ", " { $link assoc-filter } ", and more: " { $link "assocs-combinators" } } + { "Utilities: " { $link at } ", " { $link key? } ", ..." } + } + ! { $slide "Example: soundex" + ! { $vocab-link "soundex" } + ! "From Wikipedia: \"Soundex is a phonetic algorithm for indexing names by sound, as pronounced in English.\"" + ! "Factored into many small words, uses sequence and assoc operations, no explicit loops" + ! } + { $slide "Locals and lexical scope" + "Sometimes, there's no good stack solution to a problem" + "Or, you're porting existing code in a quick-and-dirty way" + "Our solution: implement named locals as a DSL in Factor" + "Influenced by Scheme and Lisp" + } + { $slide "Locals and lexical scope" + { "Define lambda words with " { $link POSTPONE: :: } } + { "Establish bindings with " { $link POSTPONE: [let } " and " { $snippet "[let*" } } + "Mutable bindings with correct semantics" + { "Named inputs for quotations with " { $link POSTPONE: [| } } + "Full closures" + } + { $slide "Locals and lexical scope" + "Two examples:" + { $vocab-link "lambda-quadratic" } + { $vocab-link "closures-example" } + } + { $slide "Locals and lexical scope" + "Locals are entirely implemented in Factor: 477 lines" + "Example of compile-time meta-programming" + "No performance penalty -vs- using the stack" + "In the base image, only 59 words out of 13,000 use locals" + } + { $slide "The parser" + "All data types have a literal syntax" + "Literal hashtables and arrays are very useful in data-driven code" + "\"Code is data\" because quotations are objects (enables Lisp-style macros)" + { $code "H{ { \"cookies\" 12 } { \"milk\" 10 } }" } + "Libraries can define new parsing words" + } + { $slide "The parser" + { "Example: URLs define a " { $link POSTPONE: URL" } " word" } + { $code "URL\" http://paste.factorcode.org/paste?id=81\"" } + } + { $slide "Example: memoization" + { "Memoization with " { $link POSTPONE: MEMO: } } + { $code + ": fib ( m -- n )" + " dup 1 > [" + " [ 1 - fib ] [ 2 - fib ] bi +" + " ] when ;" + } + "Very slow! Let's profile it..." + } + { $slide "Example: memoization" + { "Let's use " { $link POSTPONE: : } " instead of " { $link POSTPONE: MEMO: } } + { $code + "MEMO: fib ( m -- n )" + " dup 1 > [" + " [ 1 - fib ] [ 2 - fib ] bi +" + " ] when ;" + } + "Much faster" + } + { $slide "Meta-circularity" + { { $link POSTPONE: MEMO: } " is just a library word" } + { "But so is " { $link POSTPONE: : } } + "Factor's parser is written in Factor" + { "All syntax is just parsing words: " { $link POSTPONE: [ } ", " { $link POSTPONE: " } } + } + { $slide "Extensible syntax, DSLs" + "Most parsing words fall in one of two categories" + "First category: literal syntax for new data types" + "Second category: defining new types of words" + "Some parsing words are more complicated" + } + { $slide "Parser expression grammars" + { { $link POSTPONE: EBNF: } ": a complex parsing word" } + "Implements a custom syntax for expressing parsers" + { "Example: " { $vocab-link "printf-example" } } + { $code "\"cheese\" \"vegan\" \"%s is not %s\\n\" printf" } + { $code "\"Factor\" 5 \"%s is %d years old\\n\" printf" } + } + { $slide "Input/output library" + "One of Factor's strongest points: portable, full-featured, efficient" + { $vocab-link "io.files" } + { $vocab-link "io.launcher" } + { $vocab-link "io.monitors" } + { $vocab-link "io.mmap" } + { $vocab-link "http.client" } + "... and so on" + } + { $slide "Example: file system monitors" + { $code + "USE: io.monitors" + "" + ": forever ( quot -- ) '[ @ t ] loop ; inline" + "" + "\"/tmp\" t " + "'[ _ next-change . ] forever" + } + } + { $slide "Example: time server" + { $vocab-link "time-server" } + { "Demonstrates " { $vocab-link "io.servers" } " vocabulary, threads" } + } + { $slide "Example: what is my IP?" + { $vocab-link "webapps.ip" } + "Simple web app, defines a single action, use an XHTML template" + "Web framework supports more useful features: sessions, SSL, form validation, ..." + } + { $slide "Example: Yahoo! web search" + { $vocab-link "yahoo" } + { "Demonstrates " { $vocab-link "http.client" } ", " { $vocab-link "xml" } } + } + { $slide "Example: simple web browser" + { $vocab-link "webkit-demo" } + "Demonstrates Cocoa binding" + "Let's deploy a stand-alone binary with the deploy tool" + "Deploy tool generates binaries with no external dependencies" + } + { $slide "Example: environment variables" + { $vocab-link "environment" } + "Hooks are generic words which dispatch on dynamically-scoped variables" + { "Implemented in an OS-specific way: " { $vocab-link "environment.unix" } ", " { $vocab-link "environment.windows" } } + } + { $slide "Example: environment variables" + "Implementations use C FFI" + "Call C functions, call function pointers, call Factor from C, structs, floats, ..." + "No need to write C wrapper code" + } + { $slide "Implementation" + "VM: 12,000 lines of C" + "Generational garbage collection" + "core: 9,000 lines of Factor" + "Optimizing native code compiler for x86, PowerPC" + "basis: 80,000 lines of Factor" + } + { $slide "Compiler" + { "Let's look at " { $vocab-link "benchmark.mandel" } } + "A naive implementation would be very slow" + "Combinators, currying, partial application" + "Boxed complex numbers" + "Boxed floats" + { "Redundancy in " { $link absq } " and " { $link sq } } + } + { $slide "Compiler: front-end" + "Builds high-level tree SSA IR" + "Stack code with uniquely-named values" + "Inlines combinators and calls to quotations" + { $code "USING: compiler.tree.builder compiler.tree.debugger ;" "[ c pixel ] build-tree nodes>quot ." } + } + { $slide "Compiler: high-level optimizer" + "12 optimization passes" + { $link optimize-tree } + "Some passes collect information, others use the results of past analysis to rewrite the code" + } + { $slide "Compiler: propagation pass" + "Propagation pass computes types with type function" + { "Example: output type of " { $link + } " depends on the types of inputs" } + "Type: can be a class, a numeric interval, array with a certain length, tuple with certain type slots, literal value, ..." + "Mandelbrot: we infer that we're working on complex floats" + } + { $slide "Compiler: propagation pass" + "Propagation also supports \"constraints\"" + { $code "[ dup array? [ first ] when ] optimized." } + { $code "[ >fixnum dup 0 < [ 1 + ] when ] optimized." } + { $code + "[" + " >fixnum" + " dup [ -10 > ] [ 10 < ] bi and" + " [ 1 + ] when" + "] optimized." + } + } + { $slide "Compiler: propagation pass" + "Eliminates method dispatch, inlines method bodies" + "Mandelbrot: we infer that integer indices are fixnums" + "Mandelbrot: we eliminate generic arithmetic" + } + { $slide "Compiler: escape analysis" + "We identify allocations for tuples which are never returned or passed to other words (except slot access)" + { "Partial application with " { $link POSTPONE: '[ } } + "Complex numbers" + } + { $slide "Compiler: escape analysis" + { "Virtual sequences: " { $link } ", " { $link } } + { $code "[ [ . ] each ] optimized." } + { "Mandelbrot: we unbox " { $link curry } ", complex number allocations" } + } + { $slide "Compiler: dead code elimination" + "Cleans up the mess from previous optimizations" + "After inlining and dispatch elimination, dead code comes up because of unused generality" + { "No-ops like " { $snippet "0 +" } ", " { $snippet "1 *" } } + "Literals which are never used" + "Side-effect-free words whose outputs are dropped" + } + { $slide "Compiler: low level IR" + "Register-based SSA" + "Stack operations expand into low-level instructions" + { $code "[ 5 ] regs." } + { $code "[ swap ] regs." } + { $code "[ append reverse ] regs." } + } + { $slide "Compiler: low-level optimizer" + "5 optimization passes" + { $link optimize-cfg } + "Gets rid of redundancy which is hidden in high-level stack code" + } + { $slide "Compiler: optimize memory" + "First pass optimizes stack and memory operations" + { "Example: " { $link 2array } } + { { $link } " fills array with initial value" } + "What if we immediately store new values into the array?" + { $code "\\ 2array regs." } + "Mandelbrot: we optimize stack operations" + } + { $slide "Compiler: value numbering" + "Identifies expressions which are computed more than once in a basic block" + "Simplifies expressions with various identities" + "Mandelbrot: redundant float boxing and unboxing, redundant arithmetic" + } + { $slide "Compiler: dead code elimination" + "Dead code elimination for low-level IR" + "Again, cleans up results of prior optimizations" + } + { $slide "Compiler: register allocation" + "IR assumes an infinite number of registers which are only assigned once" + "Real CPUs have a finite set of registers which can be assigned any number of times" + "\"Linear scan register allocation with second-chance binpacking\"" + } + { $slide "Compiler: register allocation" + "3 steps:" + "Compute live intervals" + "Allocate registers" + "Assign registers and insert spills" + } + { $slide "Compiler: register allocation" + "Step 1: compute live intervals" + "We number all instructions consecutively" + "A live interval associates a virtual register with a list of usages" + } + { $slide "Compiler: register allocation" + "Step 2: allocate registers" + "We scan through sorted live intervals" + "If a physical register is available, assign" + "Otherwise, find live interval with furthest away use, split it, look at both parts again" + } + { $slide "Compiler: register allocation" + "Step 3: assign registers and insert spills" + "Simple IR rewrite step" + "After register allocation, one vreg may have several live intervals, and different physical registers at different points in time" + "Hence, \"second chance\"" + { "Mandelbrot: " { $code "[ c pixel ] regs." } } + } + { $slide "Compiler: code generation" + "Iterate over list of instructions" + "Extract tuple slots and call hooks" + { $vocab-link "cpu.architecture" } + "Finally, we hand the code to the VM" + { $code "\\ 2array disassemble" } + } + { $slide "Garbage collection" + "All roots are identified precisely" + "Generational copying for data" + "Mark sweep for native code" + } + { $slide "Project infrastructure" + { $url "http://factorcode.org" } + { $url "http://concatenative.org" } + { $url "http://docs.factorcode.org" } + { $url "http://planet.factorcode.org" } + "Uses our HTTP server, SSL, DB, Atom libraries..." + } + { $slide "Project infrastructure" + "Build farm, written in Factor" + "12 platforms" + "Builds Factor and all libraries, runs tests, makes binaries" + "Saves us from the burden of making releases by hand" + "Maintains stability" + } + { $slide "Community" + "#concatenative irc.freenode.net: 50-60 members" + "factor-talk@lists.sf.net: 180 subscribers" + "About 30 people have code in the Factor repository" + "Easy to get started: binaries, lots of docs, friendly community..." + } + { $slide "Future direction: Factor 1.0" + "Continue doing what we're doing:" + "Polish off some language features" + "Stability" + "Performance" + "Documentation" + "Developer tools" + } + { $slide "Future direction: Factor 2.0" + "Native threads" + "Syntax-aware Factor editor" + "Embedding Factor in C apps" + "Cross-compilation for smaller devices" + } + { $slide "That's all, folks" + "It is hard to cover everything in a single talk" + "Factor has many cool things that I didn't talk about" + "Put your prejudices aside and give it a shot!" + } + { $slide "Questions?" } +} + +: google-talk ( -- ) + google-slides "Google Tech talk" slides-window ; + +MAIN: google-talk diff --git a/google-tech-talk/summary.txt b/google-tech-talk/summary.txt new file mode 100644 index 0000000..1747a56 --- /dev/null +++ b/google-tech-talk/summary.txt @@ -0,0 +1 @@ +Slides from Google Tech Talk by Slava Pestov, October 2008 diff --git a/google-tech-talk/tags.txt b/google-tech-talk/tags.txt new file mode 100644 index 0000000..8ee64cd --- /dev/null +++ b/google-tech-talk/tags.txt @@ -0,0 +1 @@ +talks diff --git a/hmc-talk/hmc-talk.factor b/hmc-talk/hmc-talk.factor new file mode 100644 index 0000000..9a225f9 --- /dev/null +++ b/hmc-talk/hmc-talk.factor @@ -0,0 +1,491 @@ +USING: fry help.markup help.topics kernel locals math +math.functions memoize peg.ebnf slides ; +IN: talks.hmc-talk + +CONSTANT: hmc-slides +{ + { $slide "Factor!" + { $url "http://factorcode.org" } + "Development started in 2003" + "Open source (BSD license)" + "Influenced by Forth, Lisp, and Smalltalk" + "Blurs the line between language and library" + "Interactive development" + } + + { $slide "Concepts" + "Concatenative" + "Dynamic types" + "Extensible syntax" + "Fully-compiled" + "Cross-platform" + "Interactive Development" + "Code is data" + "Pervasive unit testing" + "Clickable" + } + + { $slide "Words and the stack" + "Stack based, dynamically typed" + { $code "{ 1 1 3 4 4 8 9 9 } dup duplicates diff ." } + "Words: named code snippets" + { $code ": remove-duplicates ( seq -- seq' )" " dup duplicates diff ;" } + { $code "{ 1 1 3 4 4 8 9 9 } remove-duplicates ." } + } + + { $slide "Words and the stack" + { $code + "\"/usr/local/opt/fortune/share/games/fortunes/science\"" + "ascii file-lines" + "{ \"%\" } split random" + "[ print ] each" + } + { $code + ": fortune ( -- )" + " \"/usr/local/opt/fortune/share/games/fortunes/science\"" + " ascii file-lines" + " { \"%\" } split random" + " [ print ] each ;" + } + { $code + "5 [ fortune nl ] times" + } + } + + { $slide "Vocabularies" + "Vocabularies: named sets of words" + { $link "vocab-index" } + { { $link POSTPONE: USING: } " loads dependencies" } + "Source, docs, tests in one place" + } + { $slide "Interactive development" + "Programming is hard, let's play tetris" + { $vocab-link "tetris" } + "Tetris is hard too... let's cheat" + "Factor workflow: change code, F2, test, repeat" + } + { $slide "Quotations" + "Quotation: unnamed block of code" + "Combinators: words taking quotations" + { $code "10 dup 0 < [ 1 - ] [ 1 + ] if ." } + { $code "{ -1 1 -2 0 3 } [ 0 max ] map ." } + "Partial application:" + { $code ": clamp ( seq n -- seq' ) '[ _ max ] map ;" "{ -1 1 -2 0 3 } 0 clamp" } + } + { $slide "Object system" + "CLOS with single dispatch" + "A tuple is a user-defined class which holds named values." + { $code + "TUPLE: rectangle width height ;" + "TUPLE: circle radius ;" + } + } + { $slide "Object system" + "Constructing instances:" + { $code "rectangle new" } + { $code "rectangle boa" } + "Let's encapsulate:" + { $code + ": ( w h -- r ) rectangle boa ;" + ": ( r -- c ) circle boa ;" + } + } + { $slide "Object system" + "Generic words and methods" + { $code "GENERIC: area ( shape -- n )" } + "Two methods:" + { $code + "USE: math.constants" + "" + "M: rectangle area" + " [ width>> ] [ height>> ] bi * ;" + "" + "M: circle area radius>> sq pi * ;" + } + } + { $slide "Object system" + "We can compute areas now." + { $code "100 20 area ." } + { $code "3 area ." } + } + { $slide "Object system" + "Object system handles dynamic redefinition very well" + { $code "TUPLE: person name age occupation ;" } + "Make an instance..." + } + { $slide "Object system" + "Let's add a new slot:" + { $code "TUPLE: person name age address occupation ;" } + "Fill it in with inspector..." + "Change the order:" + { $code "TUPLE: person name occupation address ;" } + } + { $slide "Object system" + "How does it work?" + "Objects are not hashtables; slot access is very fast" + "Redefinition walks the heap; expensive but rare" + } + { $slide "Object system" + "Supports \"duck typing\"" + "Two tuples can have a slot with the same name" + "Code that uses accessors will work on both" + "Accessors are auto-generated generic words" + } + { $slide "Object system" + "Predicate classes" + { $code + "PREDICATE: positive < integer 0 > ;" + "PREDICATE: negative < integer 0 < ;" + "" + "GENERIC: abs ( n -- )" + "" + "M: positive abs ;" + "M: negative abs -1 * ;" + "M: integer abs ;" + } + } + { $slide "Object system" + "More: inheritance, type declarations, read-only slots, union, intersection, singleton classes, reflection" + "Object system is entirely implemented in Factor" + } + { $slide "The parser" + "All data types have a literal syntax" + "Literal hashtables and arrays are very useful in data-driven code" + "\"Code is data\" because quotations are objects (enables Lisp-style macros)" + { $code "H{ { \"cookies\" 12 } { \"milk\" 10 } }" } + "Libraries can define new parsing words" + } + { $slide "Example: regexp" + { $vocab-link "regexp" } + "Pre-compiles regexp at parse time" + "Implemented with library code" + { $code "USE: regexp" } + { $code "\"ababbc\" \"[ab]+c\" matches? ." } + { $code "\"ababbc\" R/ [ab]+c/ matches? ." } + } + { $slide "Example: memoization" + { "Memoization with " { $link POSTPONE: MEMO: } } + { $code + ": fib ( m -- n )" + " dup 1 > [" + " [ 1 - fib ] [ 2 - fib ] bi +" + " ] when ;" + } + "Very slow! Let's profile it..." + } + { $slide "Example: memoization" + { "Let's use " { $link POSTPONE: MEMO: } " instead of " { $link POSTPONE: : } } + { $code + "MEMO: fib ( m -- n )" + " dup 1 > [" + " [ 1 - fib ] [ 2 - fib ] bi +" + " ] when ;" + } + "Much faster" + } + { $slide "Meta-circularity" + { { $link POSTPONE: MEMO: } " is just a library word" } + { "But so is " { $link POSTPONE: : } } + "Factor's parser is written in Factor" + { "All syntax is just parsing words: " { $link POSTPONE: [ } ", " { $link POSTPONE: " } } + } + { $slide "Extensible syntax, DSLs" + "Most parsing words fall in one of two categories" + "First category: literal syntax for new data types" + "Second category: defining new types of words" + "Some parsing words are more complicated" + } + + { $slide "Example: printf" + { { $link POSTPONE: EBNF: } ": a complex parsing word" } + "Implements a custom syntax for expressing parsers: like OMeta!" + { "Example: " { $vocab-link "printf" } } + { $code "\"cheese\" \"vegan\" \"%s is not %s\\n\" printf" } + { $code "\"Factor\" 5 \"%s is %d years old\\n\" printf" } + { $code "[ \"%s monkeys\" printf ] expand-macros" } + } + { $slide "Locals and lexical scope" + "Sometimes, there's no good stack solution to a problem" + "Or, you're porting existing code in a quick-and-dirty way" + "Our solution: implement named locals as a DSL in Factor" + "Influenced by Scheme and Lisp" + } + { $slide "Locals and lexical scope" + { "Define lambda words with " { $link POSTPONE: :: } } + { "Establish bindings with " { $link POSTPONE: [let } " and " { $snippet "[let*" } } + "Mutable bindings with correct semantics" + { "Named inputs for quotations with " { $link POSTPONE: [| } } + "Full closures" + } + { $slide "Locals and lexical scope" + "Combinator with 5 parameters!" + { $code + ":: branch ( a b neg zero pos -- )" + " a b = zero [ a b < neg pos if ] if ; inline" + } + "Unwieldy with the stack" + } + { $slide "Locals and lexical scope" + { $code + ": check-drinking-age ( age -- )" + " 21" + " [ \"You're underage!\" print ]" + " [ \"Grats, you're now legal\" print ]" + " [ \"Go get hammered\" print ]" + " branch ;" + } + } + { $slide "Locals and lexical scope" + "Locals are entirely implemented in Factor" + "Example of compile-time meta-programming" + "No performance penalty -vs- using the stack" + "In the base image, only 59 words out of 13,000 use locals" + } + { $slide "More about partial application" + { { $link POSTPONE: '[ } " is \"fry syntax\"" } + { $code "'[ _ + ] == [ + ] curry" } + { $code "'[ @ t ] == [ t ] compose" } + { $code "'[ _ nth @ ] == [ [ nth ] curry ] dip compose" } + { $code "'[ [ _ ] dip nth ] == [ [ ] curry dip nth ] curry" } + { "Fry and locals desugar to " { $link curry } ", " { $link compose } } + } + { $slide "Help system" + "Help markup is just literal data" + { "Look at the help for " { $link T{ link f + } } } + "These slides are built with the help system and a custom style sheet" + { $vocab-link "talks.hmc-talk" } + } + { $slide "Why stack-based?" + "Because nobody else is doing it" + "Interesting properties: concatenation is composition, chaining functions together, \"fluent\" interfaces, new combinators" + { $vocab-link "simple-rpg" } + { $code + "{ \"chicken\" \"beef\" \"pork\" \"turkey\" }" + "[ 5 short head ] map ." + } + } + { $slide "Implementation" + "VM: garbage collection, bignums, ..." + "Bootstrap image: parser, hashtables, object system, ..." + "Non-optimizing compiler" + "Stage 2 bootstrap: optimizing compiler, UI, ..." + "Full image contains machine code" + } + { $slide "Compiler" + { "Let's look at " { $vocab-link "benchmark.mandel" } } + "A naive implementation would be very slow" + "Combinators, partial application" + "Boxed complex numbers" + "Boxed floats" + { "Redundancy in " { $link absq } " and " { $link sq } } + } + { $slide "Compiler: high-level optimizer" + "High-level SSA IR" + "Type inference (classes, intervals, arrays with a fixed length, literals, ...)" + "Escape analysis and tuple unboxing" + } + { $slide "Compiler: high-level optimizer" + "Loop index becomes a fixnum, complex numbers unboxed, generic arithmetic inlined, higher-order code become first-order..." + { $code "[ c pixel ] optimized." } + } + { $slide "Compiler: low-level optimizer" + "Low-level SSA IR" + "Alias analysis" + "Value numbering" + "Linear scan register allocation" + } + { $slide "Compiler: low-level optimizer" + "Redundant stack operations eliminated, intermediate floats unboxed..." + { $code "[ c pixel ] regs." } + } + { $slide "Compiler: assembly" + "Generic assembly generated..." + { $code "[ c pixel ] disassemble" } + } + { $slide "Compiler: assembly" + "Efficient assembly generated..." + { $code "[ { fixnum fixnum } declare c pixel ] disassemble" } + } + { $slide "Garbage collection" + "All roots are identified precisely" + "Generational copying for data" + "Mark sweep for native code" + } + + { $slide "Project infrastructure" + { $url "http://factorcode.org" } + { $url "http://concatenative.org" } + { $url "http://docs.factorcode.org" } + { $url "http://planet.factorcode.org" } + { $url "http://paste.factorcode.org" } + "Uses our HTTP server, SSL, DB, Atom libraries..." + } + { $slide "Project infrastructure" + "Build farm, written in Factor" + "Multiple OS and architecture" + "Builds Factor and all libraries, runs tests, makes binaries" + "Saves us from the burden of making releases by hand" + "Maintains stability" + } + + { $slide "That's all, folks" + "It is hard to cover everything in a single talk" + "Factor has many cool things that I didn't talk about" + "Questions?" + } + + { $slide "Cool things" + { $code + "USE: xkcd" + "XKCD: 138" + } + { $code + "USE: reddit" + "\"programming\" subreddit." + } + } + + { $slide "Cool things" + { $vocab-link "minesweeper" } + { $vocab-link "game-of-life" } + { $vocab-link "boids" } + } + + { $slide "Cool things" + "8080 cpu emulator" + { $code + "\"resource:roms\" rom-root set-global" + } + { $vocab-link "roms.space-invaders" } + } + + { $slide "Cool things" + { $vocab-link "bloom-filters" } + { $vocab-link "cuckoo-filters" } + { $vocab-link "persistent" } + { $vocab-link "trees" } + { $vocab-link "tuple-arrays" } + { $vocab-link "specialized-arrays" } + } + + { $slide "Cool things" + { $code + "USE: text-to-speech" + "\"hello\" speak-text" + } + { $code + "USE: morse" + "\"hello\" play-as-morse" + } + { $code + "USE flip-text" + "\"hello\" flip-text ." + } + } + + { $slide "Cool things" + { $code + "{ 12 18 24 72 }" + "[ \"Bigger\" swap font-size associate format nl ] each" + } + + { $code + "10 [" + " \"Hello world\"" + " swap 10 / 1 over - over 1 " + " background associate format nl" + "] each" + } + } + + { $slide "Cool things" + { $code + "USE: google.charts" + "\"x = \\\\frac{-b \\\\pm \\\\sqrt {b^2-4ac}}{2a}\"" + " 200 >>width 75 >>height chart." + } + { $code + "100 [ 100 random ] replicate" + "100 [ 100 random ] replicate" + "zip chart." + } + { $code + "\"/usr/share/dict/words\" utf8 file-lines" + "[ >lower 1 head ] histogram-by" + "sort-keys " + " COLOR: green >>foreground" + " 400 >>width" + " 10 >>bar-width" + "chart." + } + } + + { $slide "Cool things" + { $code + "USE: http.client" + "\\ http-get see" + } + { $code + "\"http\" apropos" + } + { $code + "USE: images.http" + "\"https://factorcode.org/logo.png\" http-image." + } + } + + { $slide "Cool things" + "Tab completion" + { $code + "http" + } + { $code + "P\" vocab:math" + } + { $code + "COLOR: " + } + } + + { $slide "Cool things" + { $code + "USE: emojify" + "\"I :heart: Factor! :+1!\" emojify ." + } + { $code + "USE: dice" + "ROLL: 2d8+4" + "\"You do %s points of damage!\" printf" + } + } + + { $slide "Cool things" + { $code + "USING: sequences xml.syntax xml.writer ;" + "{ \"three\" \"blind\" \"mice\" }" + "[ [XML
  • <->
  • XML] ] map" + "[XML
      <->
    XML]" + "pprint-xml" + } + } + + { $slide "Cool things" + { $code + "USE: io.streams.256color" + "[ listener ] with-256color" + "\"math\" about" + } + } + + { $slide "Cool things" + { $code "./factor -run=tetris" } + { $code "./factor -run=file-server" } + { $code "./factor -run=file-monitor" } + { $code "./factor -run=tools.dns microsoft.com" } + { $code "./factor -run=tools.cal" } + } +} + +: hmc-talk ( -- ) hmc-slides "HMC Talk" slides-window ; + +MAIN: hmc-talk diff --git a/jvm-summit-talk/authors.txt b/jvm-summit-talk/authors.txt new file mode 100644 index 0000000..1901f27 --- /dev/null +++ b/jvm-summit-talk/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/jvm-summit-talk/jvm-summit-talk.factor b/jvm-summit-talk/jvm-summit-talk.factor new file mode 100644 index 0000000..b91bf01 --- /dev/null +++ b/jvm-summit-talk/jvm-summit-talk.factor @@ -0,0 +1,358 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: slides help.markup math math.private kernel sequences +slots.private ; +IN: talks.jvm-summit-talk + +CONSTANT: jvm-summit-slides +{ + { $slide "Factor language implementation" + "Goals: expressiveness, metaprogramming, performance" + "We want a language for anything from scripting DSLs to high-performance numerics" + "I assume you know a bit about compiler implementation: parser -> frontend -> optimizer -> codegen" + { "This is " { $strong "not" } " a talk about the Factor language" } + { "Go to " { $url "http://factorcode.org" } " to learn the language" } + } + { $slide "Why are dynamic languages slow?" + "Branching and indirection!" + "Runtime type checks and dispatch" + "Integer overflow checks" + "Boxed integers and floats" + "Lots of allocation of temporary objects" + } + { $slide "Interactive development" + "Code can be reloaded at any time" + "Class hierarchy might change" + "Slots may be added and removed" + "Functions might be redefined" + } + { $slide "Factor's solution" + "Factor implements most of the library in Factor" + "Library contains very generic, high-level code" + "Always compiles to native code" + "Compiler removes unused generality from high-level code" + "Inlining, specialization, partial evaluation" + "And deoptimize when assumptions change" + } + { $slide "Introduction: SSA form" + "Every identifier only has one global definition" + { + "Not SSA:" + { $code + "x = 1" + "y = 2" + "x = x + y" + "if(z < 0)" + " t = x + y" + "else" + " t = x - y" + "print(t)" + } + } + } + { $slide "Introduction: SSA form" + "Rename re-definitions and subsequent usages" + { + "Still not SSA:" + { $code + "x = 1" + "y = 2" + "x1 = x + y" + "if(z < 0)" + " t = x1 + y" + "else" + " t = x1 - y" + "print(t)" + } + } + } + { $slide "Introduction: SSA form" + "Introduce “φ functions” at control-flow merge points" + { + "This is SSA:" + { $code + "x = 1" + "y = 2" + "x1 = x + y" + "if(z < 0)" + " t1 = x1 + y" + "else" + " t2 = x1 - y" + "t3 = φ(t1,t2)" + "print(t3)" + } + } + } + { $slide "Why SSA form?" + { + "Def-use chains:" + { $list + "Defs-of: instructions that define a value" + "Uses-of: instructions that use a value" + } + "With SSA, defs-of has exactly one element" + } + } + { $slide "Def-use chains" + "Simpler def-use makes analysis more accurate." + { + "Non-SSA example:" + { $code + "if(x < 0)" + " s = new Circle" + " a = area(s1)" + "else" + " s = new Rectangle" + " a = area(s2)" + } + } + } + { $slide "Def-use chains" + { + "SSA example:" + { $code + "if(x < 0)" + " s1 = new Circle" + " a1 = area(s1)" + "else" + " s2 = new Rectangle" + " a2 = area(s2)" + "a = φ(a1,a2)" + } + + } + } + { $slide "Factor compiler overview" + "High-level SSA IR constructed from stack code" + "High level optimizer transforms high-level IR" + "Low-level SSA IR is constructed from high-level IR" + "Low level optimizer transforms low-level IR" + "Register allocator runs on low-level IR" + "Machine IR is constructed from low-level IR" + "Code generation" + } + { $slide "High-level optimizer" + "Frontend: expands macros, inline higher order functions" + "Propagation: inline methods, constant folding" + "Escape analysis: unbox tuples" + "Dead code elimination: clean up" + } + { $slide "Higher-order functions" + "Almost all control flow is done with higher-order functions" + { { $link if } ", " { $link times } ", " { $link each } } + "Calling a block is an indirect jump" + "Solution: inline higher order functions at the call site" + "Inline the block body at the higher order call site in the function" + "Record inlining in deoptimization database" + } + { $slide "Generic functions" + "A generic function contains multiple method bodies" + "Dispatches on the class of argument(s)" + "In Factor, generic functions are single dispatch" + "Almost equivalent to message passing" + } + { $slide "Tuple slot access" + "Slot readers and writers are generic functions" + "Generated automatically when you define a tuple class" + { "The generated methods call " { $link slot } ", " { $link set-slot } " primitives" } + "These primitives are not type safe; the generic dispatch performs the type checking for us" + "If class of dispatch value known statically, inline method" + "This may result in more methods inlining from additional specialization" + } + { $slide "Generic arithmetic" + { { $link + } ", " { $link * } ", etc perform a double dispatch on arguments" } + { "Fixed-precision integers (" { $link fixnum } "s) upgrade to " { $link bignum } "s automatically" } + "Floats and complex numbers are boxed, heap-allocated" + "Propagation of classes helps for floats" + "But not for fixnums, because of overflow checks" + "So we also propagate integer intervals" + "Interval arithmetic: etc, [a,b] + [c,d] = [a+c,b+d]" + } + { $slide "Slot value propagation" + "Complex numbers are even trickier" + "We can have a complex number with integer components, float components" + "Even if we inline complex arithmetic methods, still dispatching on components" + "Solution: propagate slot info" + } + { $slide "Constraint propagation" + "Contrieved example:" + { $code + "x = •" + "b = isa(x,array)" + "if(b)" + " a = length(x)" + "else" + " b = length(x)" + "c = φ(a,b)" + } + { "We should be able to inline the call to " { $snippet "length" } " in the true branch" } + } + { $slide "Constraint propagation" + "We build a table:" + { $code + "b true => x is array" + "b false => x is ~array" + } + { "In true branch, apply all " { $snippet "b true" } " constraints" } + { "In false branch, apply all " { $snippet "b false" } " constraints" } + } + { $slide "Going further" + "High-level optimizer eliminates some dispatch overhead and allocation" + { + { "Let's take a look at the " { $link float+ } " primitive" } + { $list + "No type checking anymore... but" + "Loads two tagged pointers from operand stack" + "Unboxes floats" + "Adds two floats" + "Boxes float result and perform a GC check" + } + } + } + { $slide "Low-level optimizer" + "Frontend: construct LL SSA IR from HL SSA IR" + "Alias analysis: remove redundant slot loads/stores" + "Value numbering: simplify arithmetic" + "Representation selection: eliminate boxing" + "Dead code elimination: clean up" + "Register allocation" + } + { $slide "Constructing low-level IR" + { "Low-level IR is a " { $emphasis "control flow graph" } " of " { $emphasis "basic blocks" } } + "A basic block is a list of instructions" + "Register-based IR; infinite, uniform register file" + { "Instructions:" + { $list + "Subroutine calls" + "Machine arithmetic" + "Load/store values on operand stack" + "Box/unbox values" + } + } + } + { $slide "Inline allocation and GC checks" + { + "Allocation of small objects can be done in a few instructions:" + { $list + "Bump allocation pointer" + "Write object header" + "Fill in payload" + } + } + "Multiple allocations in the same basic block only need a single GC check; saves on a conditional branch" + } + { $slide "Alias analysis" + "Factor constructors are just ordinary functions" + { "They call a primitive constructor: " { $link new } } + "When a new object is constructed, it has to be initialized" + "... but the user's constructor probably fills in all the slots again with actual values" + "Local alias analysis eliminates redundant slot loads and stores" + } + { $slide "Value numbering" + { "A form of " { $emphasis "redundancy elimination" } } + "Requires use of SSA form in order to work" + "Define an equivalence relation over SSA values" + "Assign a “value number” to each SSA value" + "If two values have the same number, they will always be equal at runtime" + } + { $slide "Types of value numbering" + "Many variations: algebraic simplifications, various rewrite rules can be tacked on" + "Local value numbering: in basic blocks" + "Global value numbering: entire procedure" + "Factor only does local value numbering" + } + { $slide "Value graph and expressions" + { $table + { + { + "Basic block:" + { $code + "x = •" + "y = •" + "a = x + 1" + "b = a + 1" + "c = x + 2" + "d = b - c" + "e = y + d" + } + } + { + "Value numbers:" + { $code + "V1: •" + "V2: •" + "V3: 1" + "V4: 2" + "V5: (V1 + V3)" + "V6: (V5 + V3)" + "V7: (V3 + V4)" + "V8: (V6 - V7)" + "V9: (V2 + V8)" + } + } + } + } + } + { $slide "Expression simplification" + { + "Constant folding: if V1 and V2 are constants " + { $snippet "(V1 op V2)" } + " can be evaluated at compile-time" + } + { + "Reassociation: if V2 and V3 are constants " + { $code "((V1 op V2) op V3) => (V1 op (V2 op V3))" } + } + { + "Algebraic identities: if V2 is constant 0, " + { $code "(V1 + V2) => V1" } + } + { + "Strength reduction: if V2 is a constant power of two, " + { $code "(V1 * V2) => (V1 << log2(V2))" } + } + "etc, etc, etc" + } + { $slide "Representation selection overview" + "Floats and SIMD vectors need to be boxed" + "Representation: tagged pointer, unboxed float, unboxed SIMD value..." + "When IR is built, no boxing or unboxing instructions inserted" + "Representation selection pass makes IR consistent" + } + { $slide "Representation selection algorithm" + { + "For each SSA value:" + { $list + "Compute possible representations" + "Compute cost of each representation" + "Pick representation with minimum cost" + } + } + { + "For each instruction:" + { $list + "If it expects a value to be in a different representation, insert box or unbox code" + } + } + } + { $slide "Register allocation" + "Linear scan algorithm used in Java HotSpot Client" + "Described in Christian Wimmer's masters thesis" + "Works fine on x86-64, not too great on x86-32" + "Good enough since basic blocks tend to be short, with lots of procedure calls" + "Might switch to graph coloring eventually" + } + { $slide "Compiler tools" + "Printing high level IR" + "Printing low level IR" + "Disassembly" + "Display call tree" + "Display control flow graph" + "Display dominator tree" + } +} + +: jvm-summit-talk ( -- ) + jvm-summit-slides "JVM Summit talk" slides-window ; + +MAIN: jvm-summit-talk diff --git a/jvm-summit-talk/summary.txt b/jvm-summit-talk/summary.txt new file mode 100644 index 0000000..769abbc --- /dev/null +++ b/jvm-summit-talk/summary.txt @@ -0,0 +1 @@ +Slides from Slava's talk at JVM Language Summit 2009 diff --git a/jvm-summit-talk/tags.txt b/jvm-summit-talk/tags.txt new file mode 100644 index 0000000..8ee64cd --- /dev/null +++ b/jvm-summit-talk/tags.txt @@ -0,0 +1 @@ +talks diff --git a/minneapolis-talk/authors.txt b/minneapolis-talk/authors.txt new file mode 100644 index 0000000..1901f27 --- /dev/null +++ b/minneapolis-talk/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/minneapolis-talk/deploy.factor b/minneapolis-talk/deploy.factor new file mode 100644 index 0000000..ea200ce --- /dev/null +++ b/minneapolis-talk/deploy.factor @@ -0,0 +1,11 @@ +USING: tools.deploy.config ; +V{ + { deploy-ui? t } + { deploy-io 3 } + { deploy-reflection 1 } + { deploy-math? t } + { deploy-word-props? f } + { deploy-c-types? f } + { "stop-after-last-window?" t } + { deploy-name "Minnesota Talk" } +} diff --git a/minneapolis-talk/minneapolis-talk.factor b/minneapolis-talk/minneapolis-talk.factor new file mode 100644 index 0000000..4cae92b --- /dev/null +++ b/minneapolis-talk/minneapolis-talk.factor @@ -0,0 +1,183 @@ +USING: slides help.markup math arrays hashtables namespaces +sequences kernel parser memoize ; +IN: talks.minneapolis-talk + +CONSTANT: minneapolis-slides +{ + { $slide "What is Factor?" + "Dynamically typed, stack language" + "Have our cake and eat it too" + "Research -vs- production" + "High level -vs- performance" + "Interactive -vs- stand-alone apps" + } + { $slide "The view from 10,000 feet" + "Influenced by Forth, Lisp, Joy, Smalltalk, even Java..." + "Vocabularies: modules" + "Words: named functions, classes, variables" + "Combinators: higher-order functions" + "Quotations: anonymous functions" + } + { $slide "Stack-based programming" + { "Most languages are " { $emphasis "applicative" } } + "Words pop inputs from the stack and push outputs on the stack" + "Literals are pushed on the stack" + { $code "{ 1 2 } { 7 } append reverse sum ." } + } + { $slide "Stack-based programming" + "With the stack you can omit unnecessary names" + "You can still name things: lexical/dynamic variables, sequences, associations, objects, ..." + } + { $slide "Functional programming" + "A quotation is a sequence of literals and words" + "Combinators replace imperative-style loops" + "A simple example:" + { $code "10 [ \"Hello world\" print ] times" } + { "Partial application: " { $link curry } } + { $code "{ 3 1 3 3 7 } [ 5 + ] map ." } + { $code "{ 3 1 3 3 7 } 5 [ + ] curry map ." } + } + { $slide "Word definitions" + { $code ": name ( inputs -- outputs )" + " definition ;" } + "Stack effect comments document stack inputs and outputs." + "Example from previous slide:" + { $code ": add-each ( seq n -- newseq )" + " [ + ] curry map ;" } + { $code "{ 3 1 3 3 7 } 5 add-each ." } + } + { $slide "Object-oriented programming" + { "Define a tuple class and a constructor:" + { $code + "TUPLE: person name address ;" + "C: person" + } } + { "Create an instance:" + { $code + "\"Cosmo Kramer\"" + "\"100 Blah blah St, New York\"" + "" + } } + } + { $slide "Object-oriented programming" + "We can inspect it and edit objects" + "We can reshape the class!" + { $code "TUPLE: person" "name address age phone-number ;" } + { $code "TUPLE: person" "name address phone-number age ;" } + } + { $slide "An example" + { $code + "TUPLE: square dimension ;" + "C: square" + "" + "TUPLE: circle radius ;" + "C: circle" + "" + "TUPLE: rectangle width height ;" + "C: rectangle" + } + } + STRIP-TEASE: + $slide "An example" + { $code + "USE: math.constants" + "GENERIC: area ( shape -- meters^2 )" + "M: square area square-dimension sq ;" + "M: circle area circle-radius sq pi * ;" + "M: rectangle area" + " dup rectangle-width" + " swap rectangle-height * ;" + } + ; + + { $slide "An example" + { $code "10 area ." } + { $code "18 area ." } + { $code "20 40 area ." } + } + { $slide "Meta language" + "Here's fibonacci:" + { $code + ": fib ( x -- y )" + " dup 1 > [" + " 1 - dup fib swap 1 - fib +" + " ] when ;" + } + "It is slow:" + { $code + "35 [ fib ] map ." + } + "Let's profile it!" + } + { $slide "Memoization" + { { $link POSTPONE: : } " is just another word" } + "What if we could define a word which caches its results?" + { "The " { $vocab-link "memoize" } " library provides such a feature" } + { "Just change " { $link POSTPONE: : } " to " { $link POSTPONE: MEMO: } } + } + { $slide "Memoization" + { $code + "USE: memoize" + "" + "MEMO: fib ( x -- y )" + " dup 1 > [" + " 1 - dup fib swap 1 - fib +" + " ] when ;" + } + "It is faster:" + { $code + "35 [ fib ] map ." + } + } + { $slide "The Factor UI" + "Written in Factor" + "Renders with OpenGL" + "Backends for Windows, X11, Cocoa" + "You can call Windows, X11, Cocoa APIs directly too" + "OpenGL 2.1 shaders, OpenAL 3D audio..." + } + { $slide "Live coding demo" + + } + { $slide "C library interface" + "Efficient" + "No need to write C code" + "Supports floats, structs, unions, ..." + "Function pointers, callbacks" + } + { $slide "Live coding demo" + + } + { $slide "Deployment" + { "Let's play " { $vocab-link "tetris" } } + } + { $slide "Implementation" + "Portable: Windows, Mac OS X, Linux" + "Non-optimizing compiler" + "Optimizing compiler: x86, x86-64, PowerPC, ARM" + "Generational garbage collector" + "Non-blocking I/O" + } + { $slide "Some statistics" + "VM: 11,800 lines of C" + "Core library: 22,600 lines of Factor" + "Docs, tests, extra libraries: 117,000 lines of Factor" + } + { $slide "But wait, there's more!" + "Web server and framework, syntax highlighting, Ogg Theora video, SMTP, embedded Prolog, efficient unboxed arrays, XML, Unicode 5.0, memory mapped files, regular expressions, LDAP, database access, coroutines, Factor->JavaScript compiler, JSON, pattern matching, advanced math, parser generators, serialization, RSS/Atom, ..." + } + { $slide "Community" + "Factor development began in 2003" + "About a dozen contributors" + "Handful of \"core contributors\"" + { "Web site: " { $url "http://factorcode.org" } } + "IRC: #concatenative on irc.freenode.net" + "Mailing list: factor-talk@lists.sf.net" + } + { $slide "Questions?" } +} + +: minneapolis-talk ( -- ) + minneapolis-slides "Minneapolis talk" slides-window ; + +MAIN: minneapolis-talk diff --git a/minneapolis-talk/summary.txt b/minneapolis-talk/summary.txt new file mode 100644 index 0000000..ef8d1bd --- /dev/null +++ b/minneapolis-talk/summary.txt @@ -0,0 +1 @@ +Slides for a talk at Ruby.mn, Minneapolis, MN, January 2008 diff --git a/minneapolis-talk/tags.txt b/minneapolis-talk/tags.txt new file mode 100644 index 0000000..8ee64cd --- /dev/null +++ b/minneapolis-talk/tags.txt @@ -0,0 +1 @@ +talks diff --git a/otug-talk/2bi.tiff b/otug-talk/2bi.tiff new file mode 100644 index 0000000000000000000000000000000000000000..16c0777254962273281d6df6760975c90ff56f80 GIT binary patch literal 11744 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 literal 0 HcmV?d00001 diff --git a/otug-talk/2bi_at.tiff b/otug-talk/2bi_at.tiff new file mode 100644 index 0000000000000000000000000000000000000000..e41ab98eeb4132fd3cb2e0ae7fa6ead6263294be GIT binary patch literal 13728 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 In-m592kY>u{Qv*} literal 0 HcmV?d00001 diff --git a/otug-talk/2bi_star.tiff b/otug-talk/2bi_star.tiff new file mode 100644 index 0000000000000000000000000000000000000000..f457ce5481a0d86c2db8816b03f7bbc9c1c08476 GIT binary patch literal 13924 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 XZK9=>kdUAmzM%;>SW|OfY$*6YG-qSv literal 0 HcmV?d00001 diff --git a/otug-talk/bi_at.tiff b/otug-talk/bi_at.tiff new file mode 100644 index 0000000000000000000000000000000000000000..07d25bcd01e25edf0e99f12968a6b9c2493f38e7 GIT binary patch literal 8848 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 ZVj}cZRpa8~R04NqLITZH36Jsz{{=X_sWJcn literal 0 HcmV?d00001 diff --git a/otug-talk/bi_star.tiff b/otug-talk/bi_star.tiff new file mode 100644 index 0000000000000000000000000000000000000000..17f3350b51b562129d4c90142c31986fce640959 GIT binary patch literal 9784 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 literal 0 HcmV?d00001 diff --git a/otug-talk/otug-talk.factor b/otug-talk/otug-talk.factor new file mode 100644 index 0000000..bb18d72 --- /dev/null +++ b/otug-talk/otug-talk.factor @@ -0,0 +1,342 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: slides help.markup math arrays hashtables namespaces +kernel sequences parser memoize io.encodings.binary +locals kernel.private help.vocabs assocs quotations +tools.annotations tools.crossref help.topics math.functions +compiler.tree.optimizer compiler.cfg.optimizer fry +ui.gadgets.panes tetris tetris.game combinators generalizations +multiline sequences.private ; +IN: talks.otug-talk + +: $tetris ( element -- ) + drop [ gadget. ] ($block) ; + +CONSTANT: otug-slides +{ + { $slide "Factor!" + { $url "http://factorcode.org" } + "Development started in 2003" + "Open source (BSD license)" + "Influenced by Forth, Lisp, and Smalltalk" + "Blurs the line between language and library" + "Interactive development" + } + { $slide "Part 1: the language" } + { $slide "Basics" + "Stack based, dynamically typed" + { "A " { $emphasis "word" } " is a named piece of code" } + { "Values are passed between words on a " { $emphasis "stack" } } + "Code evaluates left to right" + "Example:" + { $code "2 3 + ." } + } + { $slide "Quotations" + { "A " { $emphasis "quotation" } " is a block of code pushed on the stack" } + { "Syntax: " { $snippet "[ ... ]" } } + "Example:" + { $code + "\"/etc/passwd\" ascii file-lines" + "[ \"#\" head? ] reject" + "[ \":\" split first ] map" + "." + } + } + { $slide "Words" + { "We can define new words with " { $snippet ": name ... ;" } " syntax" } + { $code ": remove-comments ( lines -- lines' )" " [ \"#\" head? ] reject ;" } + { "Words are grouped into " { $emphasis "vocabularies" } } + { $link "vocab-index" } + "Libraries and applications are vocabularies" + { $vocab-link "spheres" } + } + { $slide "Constructing quotations" + { "Suppose we want a " { $snippet "remove-comments*" } " word" } + { $code ": remove-comments* ( lines string -- lines' )" " [ ??? head? ] reject ;" } + { "We use " { $link POSTPONE: '[ } " instead of " { $link POSTPONE: [ } } + { "Create “holes” with " { $link POSTPONE: _ } } + "Holes filled in left to right when quotation pushed on the stack" + } + { $slide "Constructing quotations" + { $code ": remove-comments* ( lines string -- lines' )" " '[ _ head? ] reject ;" "" ": remove-comments ( lines -- lines' )" " \"#\" remove-comments* ;" } + { { $link POSTPONE: @ } " inserts a quotation" } + { $code ": replicate ( n quot -- seq )" " '[ drop @ ] map ;" } + { $code "10 [ 1 10 [a,b] random ] replicate ." } + } + { $slide "Combinators" + { "A " { $emphasis "combinator" } " is a word taking quotations as input" } + { "Used for control flow, data flow, iteration" } + { $code "100 [ 5 mod 3 = [ \"Fizz!\" print ] when ] each" } + { "Control flow: " { $link if } ", " { $link when } ", " { $link unless } ", " { $link cond } } + { "Iteration: " { $link map } ", " { $link filter } ", " { $link all? } ", ..." } + } + { $slide "Data flow combinators - simple example" + "All examples so far used “pipeline style”" + "What about using a value more than once, or operating on values not at top of stack?" + { $code "{ 10 70 54 } [ sum ] [ length ] bi / ." } + { $code "5 [ 1 + ] [ sqrt ] [ 1 - ] tri 3array ." } + } + { $slide "Data flow combinators - cleave family" + { { $link bi } ", " { $link tri } ", " { $link cleave } } + { $image "resource:extra/talks/otug-talk/bi.tiff" } + } + { $slide "Data flow combinators - cleave family" + { { $link 2bi } ", " { $link 2tri } ", " { $link 2cleave } } + { $image "resource:extra/talks/otug-talk/2bi.tiff" } + } + { $slide "Data flow combinators" + "First, let's define a data type:" + { $code "TUPLE: person first-name last-name ;" } + "Make an instance:" + { $code "person new" " \"Joe\" >>first-name" " \"Sixpack\" >>last-name" } + } + { $slide "Data flow combinators" + "Let's do stuff with it:" + { $code + "[ first-name>> ] [ last-name>> ] bi" + "[ 2 head ] [ 5 head ] bi*" + "[ >upper ] bi@" + "\".\" glue ." + } + } + { $slide "Data flow combinators - spread family" + { { $link bi* } ", " { $link tri* } ", " { $link spread } } + { $image "resource:extra/talks/otug-talk/bi_star.tiff" } + } + { $slide "Data flow combinators - spread family" + { { $link 2bi* } } + { $image "resource:extra/talks/otug-talk/2bi_star.tiff" } + } + { $slide "Data flow combinators - apply family" + { { $link bi@ } ", " { $link tri@ } ", " { $link napply } } + { $image "resource:extra/talks/otug-talk/bi_at.tiff" } + } + { $slide "Data flow combinators - apply family" + { { $link 2bi@ } } + { $image "resource:extra/talks/otug-talk/2bi_at.tiff" } + } + { $slide "Shuffle words" + "When data flow combinators are not enough" + { $link "shuffle-words" } + "Lower-level, Forth/PostScript-style stack manipulation" + } + { $slide "Locals" + "When data flow combinators and shuffle words are not enough" + "Name your input parameters" + "Used in about 1% of all words" + } + { $slide "Locals example" + "Area of a triangle using Heron's formula" + { $code + ":: area ( a b c -- x ) + a b c + + 2 / :> p + p + p a - * + p b - * + p c - * sqrt ;" + } + } + { $slide "Previous example without locals" + "A bit unwieldy..." + { $code + ": area ( a b c -- x ) + [ ] [ + + 2 / ] 3bi + [ '[ _ - ] tri@ ] [ neg ] bi + * * * sqrt ;" } + } + { $slide "More idiomatic version" + "But there's a trick: put the points in an array" + { $code ": v-n ( v n -- w ) '[ _ - ] map ; + +: area ( points -- x ) + [ 0 suffix ] [ sum 2 / ] bi + v-n product sqrt ;" } + } + ! { $slide "The parser" + ! "All data types have a literal syntax" + ! "Literal hashtables and arrays are very useful in data-driven code" + ! { $code "H{ { \"cookies\" 12 } { \"milk\" 10 } }" } + ! "Libraries can define new parsing words" + ! } + { $slide "Programming without named values" + "Minimal glue between words" + "Easy multiple return values" + { "Avoid useless variable names: " { $snippet "x" } ", " { $snippet "n" } ", " { $snippet "a" } ", ..." } + { { $link at } " and " { $link at* } } + { $code "at* [ ... ] [ ... ] if" } + } + { $slide "Stack language idioms" + "Enables new idioms not possible before" + "We get the effect of “keyword parameters” for free" + { $vocab-link "smtp-example" } + } + { $slide "“Perfect” factoring" + { $table + { { $link head } { $link head-slice } } + { { $link tail } { $link tail-slice } } + } + { "Modifier: " { $link from-end } } + { "Modifier: " { $link short } } + "4*2*2=16 operations, 6 words!" + } + { $slide "Modifiers" + "“Modifiers” can express MN combinations using M+N words" + { $code + "\"Hello, Joe\" 4 head ." + "\"Hello, Joe\" 3 tail ." + "\"Hello, Joe\" 3 from-end tail ." + } + { $code + "\"Hello world\" 5 short head ." + "\"Hi\" 5 short tail ." + } + } + { $slide "Modifiers" + { "C-style " { $snippet "while" } " and " { $snippet "do while" } " loops" } + } + { $slide "Modifiers" + { $code ": bank ( n -- n )" " readln string>number +" " dup \"Balance: $\" write . ;" } + { $code "0 [ dup 0 > ] [ bank ] while" } + } + { $slide "Modifiers" + { $code "0 [ dup 0 > ] [ bank ] [ ] do while" } + { { $link do } " executes one iteration of a " { $link while } " loop" } + { { $link while } " calls " { $link do } } + } + { $slide "More “pipeline style” code" + { "Suppose we want to get the price of the customer's first order, but any one of the steps along the way could be a nil value (" { $link f } " in Factor):" } + { $code + "dup [ orders>> ] when" + "dup [ first ] when" + "dup [ price>> ] when" + } + } + { $slide "This is hard with mainstream syntax!" + { $code + "var customer = ...; +var orders = (customer == null ? null : customer.orders); +var order = (orders == null ? null : orders[0]); +var price = (order == null ? null : order.price);" } + } + { $slide "An ad-hoc solution" + "Something like..." + { $code "var price = customer.?orders.?[0].?price;" } + } + ! { $slide "Stack languages are fundamental" + ! "Very simple semantics" + ! "Easy to generate stack code programmatically" + ! "Everything is almost entirely library code in Factor" + ! "Factor is easy to extend" + ! } + { $slide "Part 2: the implementation" } + { $slide "Interactive development" + { $tetris } + } + { $slide "Application deployment" + { $vocab-link "webkit-demo" } + "Demonstrates Cocoa binding" + "Let's deploy a stand-alone binary with the deploy tool" + "Deploy tool generates binaries with no external dependencies" + } + { $slide "The UI" + "Renders with OpenGL" + "Backends for Cocoa, Windows, X11: managing windows, input events, clipboard" + "Cross-platform API" + } + { $slide "UI example" + { $code + " + { 5 5 } >>gap + 1 >>fill + \"Hello world!\"