]> gitweb.factorcode.org Git - factor.git/blobdiff - core/kernel/kernel-docs.factor
Merge OneEyed's patch
[factor.git] / core / kernel / kernel-docs.factor
index da79a928ad571a7582c972f8aaba621b26f57eaa..9c5d6f56ea22a4642683575dd715dba38e0afaed 100644 (file)
@@ -57,6 +57,7 @@ HELP: clear
 { $description "Clears the data stack." } ;
 
 HELP: build
+{ $values { "n" integer } }
 { $description "The current build number. Factor increments this number whenever a new boot image is created." } ;
 
 HELP: hashcode*
@@ -447,7 +448,7 @@ HELP: 2tri@
 
 HELP: bi-curry
 { $values { "x" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( x -- ... )" } } { "p'" { $snippet "[ x p ]" } } { "q'" { $snippet "[ x q ]" } } }
-{ $description "Curries " { $snippet "x" } " onto " { $snippet "p" } " and " { $snippet "q" } "." }
+{ $description "Partially applies " { $snippet "p" } " and " { $snippet "q" } " to " { $snippet "x" } "." }
 { $notes
   "The following two lines are equivalent:"
   { $code
@@ -477,7 +478,7 @@ HELP: tri-curry
   { "q'" { $snippet "[ x q ]" } }
   { "r'" { $snippet "[ x r ]" } }
 }
-{ $description "Curries " { $snippet "x" } " onto " { $snippet "p" } ", " { $snippet "q" } " and " { $snippet "q" } "." }
+{ $description "Partially applies " { $snippet "p" } ", " { $snippet "q" } " and " { $snippet "r" } " to " { $snippet "x" } "." }
 { $notes
   "The following two lines are equivalent:"
   { $code
@@ -493,7 +494,7 @@ HELP: tri-curry
 
 HELP: bi-curry*
 { $values { "x" object } { "y" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( y -- ... )" } } { "p'" { $snippet "[ x p ]" } } { "q'" { $snippet "[ y q ]" } } }
-{ $description "Curries " { $snippet "x" } " onto " { $snippet "p" } ", and " { $snippet "y" } " onto " { $snippet "q" } "." }
+{ $description "Partially applies " { $snippet "p" } " to " { $snippet "x" } ", and " { $snippet "q" } " to " { $snippet "y" } "." }
 { $notes
   "The following two lines are equivalent:"
   { $code
@@ -519,14 +520,58 @@ HELP: bi-curry*
 HELP: tri-curry*
 { $values
   { "x" object }
+  { "y" object }
+  { "z" object }
   { "p" { $quotation "( x -- ... )" } }
-  { "q" { $quotation "( x -- ... )" } }
-  { "r" { $quotation "( x -- ... )" } }
+  { "q" { $quotation "( y -- ... )" } }
+  { "r" { $quotation "( z -- ... )" } }
   { "p'" { $snippet "[ x p ]" } }
-  { "q'" { $snippet "[ x q ]" } }
-  { "r'" { $snippet "[ x r ]" } }
+  { "q'" { $snippet "[ y q ]" } }
+  { "r'" { $snippet "[ z r ]" } }
+}
+{ $description "Partially applies " { $snippet "p" } " to " { $snippet "x" } ", " { $snippet "q" } " to " { $snippet "y" } " and " { $snippet "r" } " to " { $snippet "z" } "." }
+{ $notes
+  "The following two lines are equivalent:"
+  { $code
+    "[ p ] [ q ] [ r ] tri-curry* [ call ] tri@"
+    "[ p ] [ q ] [ r ] tri*"
+  }
+  "The combination " { $snippet "tri-curry* tri" } " is equivalent to a stack shuffle preceding " { $link 2tri* } ":"
+  { $code
+    "[ p ] [ q ] [ r ] tri-curry* tri"
+    "[ [ over ] dip over ] dip [ p ] [ q ] [ r ] 2tri*"
+  }
+} ;
+
+HELP: bi-curry@
+{ $values { "x" object } { "y" object } { "q" { $quotation "( obj -- ... )" } } { "p'" { $snippet "[ x q ]" } } { "q'" { $snippet "[ y q ]" } } }
+{ $description "Partially applies " { $snippet "q" } " to " { $snippet "x" } " and " { $snippet "y" } "." }
+{ $notes
+  "The following two lines are equivalent:"
+  { $code
+    "[ q ] bi-curry@"
+    "[ q ] [ q ] bi-curry*"
+  }
+} ;
+
+HELP: tri-curry@
+{ $values
+  { "x" object }
+  { "y" object }
+  { "z" object }
+  { "q" { $quotation "( obj -- ... )" } }
+  { "p'" { $snippet "[ x q ]" } }
+  { "q'" { $snippet "[ y q ]" } }
+  { "r'" { $snippet "[ z q ]" } }
 }
-{ $description "Curries " { $snippet "x" } " onto " { $snippet "p" } ", " { $snippet "q" } " and " { $snippet "q" } "." } ;
+{ $description "Partially applies " { $snippet "q" } " to " { $snippet "x" } ", " { $snippet "y" } " and " { $snippet "z" } "." }
+{ $notes
+  "The following two lines are equivalent:"
+  { $code
+    "[ q ] tri-curry@"
+    "[ q ] [ q ] [ q ] tri-curry*"
+  }
+} ;
 
 HELP: if
 { $values { "?" "a generalized boolean" } { "true" quotation } { "false" quotation } }
@@ -720,15 +765,15 @@ HELP: 4dip
 } ;
 
 HELP: while
-{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } }
 { $description "Calls " { $snippet "body" } " until " { $snippet "pred" } " returns " { $link f } "." } ;
 
 HELP: until
-{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } }
 { $description "Calls " { $snippet "body" } " until " { $snippet "pred" } " returns " { $link t } "." } ;
 
 HELP: do
-{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } }
 { $description "Executes one iteration of a " { $link while } " or " { $link until } " loop." } ;
 
 HELP: loop
@@ -749,18 +794,11 @@ ARTICLE: "looping-combinators" "Looping combinators"
 "In most cases, loops should be written using high-level combinators (such as " { $link "sequences-combinators" } ") or tail recursion. However, sometimes, the best way to express intent is with a loop."
 { $subsection while }
 { $subsection until }
-"The above two combinators take a " { $snippet "tail" } " quotation. Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
-{ $code
-    "[ P ] [ Q ] [ T ] while"
-    "[ P ] [ Q ] [ ] while T"
-}
-"However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference."
-$nl
 "To execute one iteration of a loop, use the following word:"
 { $subsection do }
 "This word is intended as a modifier. The normal " { $link while } " loop never executes the body if the predicate returns first on the first iteration. To ensure the body executes at least once, use " { $link do } ":"
 { $code
-    "[ P ] [ Q ] [ T ] do while"
+    "[ P ] [ Q ] do while"
 }
 "A simpler looping combinator which executes a single quotation until it returns " { $link f } ":"
 { $subsection loop } ;
@@ -945,17 +983,49 @@ ARTICLE: "curried-dataflow" "Curried dataflow combinators"
 { $subsection tri-curry@ }
 { $see-also "dataflow-combinators" } ;
 
+ARTICLE: "compositional-examples" "Examples of compositional combinator usage"
+"Consider printing the same message ten times:"
+{ $code ": print-10 ( -- ) 10 [ \"Hello, world.\" print ] times ;" }
+"if we wanted to abstract out the message into a parameter, we could keep it on the stack between iterations:"
+{ $code ": print-10 ( message -- ) 10 [ dup print ] times drop ;" }
+"However, keeping loop-invariant values on the stack doesn't always work out nicely. For example, a word to subtract a value from each element of a sequence:"
+{ $code ": subtract-n ( seq n -- seq' ) swap [ over - ] map nip ;" }
+"Three shuffle words are required to pass the value around. Instead, the loop-invariant value can be partially applied to a quotation using " { $link curry } ", yielding a new quotation that is passed to " { $link map } ":"
+{ $example
+  "USING: kernel math prettyprint sequences ;"
+  ": subtract-n ( seq n -- seq' ) [ - ] curry map ;"
+  "{ 10 20 30 } 5 subtract-n ."
+  "{ 5 15 25 }"
+}
+"Now consider the word that is dual to the one above; instead of subtracting " { $snippet "n" } " from each stack element, it subtracts each element from " { $snippet "n" } "."
+$nl
+"One way to write this is with a pair of " { $link swap } "s:"
+{ $code ": n-subtract ( n seq -- seq' ) swap [ swap - ] curry map ;" }
+"Since this pattern comes up often, " { $link with } " encapsulates it:"
+{ $example
+  "USING: kernel math prettyprint sequences ;"
+  ": n-subtract ( n seq -- seq' ) [ - ] with map ;"
+  "30 { 10 20 30 } n-subtract ."
+  "{ 20 10 0 }"
+}
+{ $see-also "fry.examples" } ;
+
 ARTICLE: "compositional-combinators" "Compositional combinators"
-"Quotations can be composed using efficient quotation-specific operations:"
+"Certain combinators transform quotations to produce a new quotation."
+{ $subsection "compositional-examples" }
+"Fundamental operations:"
 { $subsection curry }
+{ $subsection compose }
+"Derived operations:"
 { $subsection 2curry }
 { $subsection 3curry }
 { $subsection with }
-{ $subsection compose }
 { $subsection prepose }
+"These operations run in constant time, and in many cases are optimized out altogether by the " { $link "compiler" } ". " { $link "fry" } " are an abstraction built on top of these operations, and code that uses this abstraction is often clearer than direct calls to the below words."
+$nl
 "Curried dataflow combinators can be used to build more complex dataflow by combining cleave, spread and apply patterns in various ways."
 { $subsection "curried-dataflow" }
-"Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } "." ;
+"Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } ". However, such runtime quotation manipulation will not be optimized by the optimizing compiler." ;
 
 ARTICLE: "implementing-combinators" "Implementing combinators"
 "The following pair of words invoke words and quotations reflectively:"