diff --git a/Factor.app/Contents/Info.plist b/Factor.app/Contents/Info.plist index ca0e6d5f8a..a8943d0d32 100644 --- a/Factor.app/Contents/Info.plist +++ b/Factor.app/Contents/Info.plist @@ -32,7 +32,7 @@ CFBundlePackageType APPL NSHumanReadableCopyright - Copyright © 2003-2007, Slava Pestov and friends + Copyright © 2003-2008, Slava Pestov and friends NSServices diff --git a/core/bootstrap/image/image.factor b/core/bootstrap/image/image.factor index cb73dc387e..cb83dd9488 100755 --- a/core/bootstrap/image/image.factor +++ b/core/bootstrap/image/image.factor @@ -404,7 +404,7 @@ M: quotation ' [ { dictionary source-files builtins - update-map class<=-cache class<=>-cache + update-map class<=-cache class-not-cache classes-intersect-cache class-and-cache class-or-cache } [ dup get swap bootstrap-word set ] each diff --git a/core/classes/algebra/algebra-docs.factor b/core/classes/algebra/algebra-docs.factor index 3903da1ebc..810bdbe10f 100755 --- a/core/classes/algebra/algebra-docs.factor +++ b/core/classes/algebra/algebra-docs.factor @@ -23,30 +23,19 @@ ARTICLE: "class-linearization" "Class linearization" "If a generic word defines a method on a mixin class A and another class B, and B is the only instance of A, there is an ambiguity because A and B are equal as sets; any object that is an instance of one is an instance of both." { "If a generic word defines methods on two union classes which are incomparable but not disjoint, for example " { $link sequence } " and " { $link number } ", there is an ambiguity because the generic word may be called on an object that is an instance of both unions." } } -"These difficulties are resolved by imposing a linear order on classes, computed as follows for two classes A and B:" +"The first ambiguity is resolved with a tie-breaker that compares metaclasses. The intrinsic meta-class order, from most-specific to least-specific:" { $list - "If A and B are the same class (not just equal as sets), then comparison stops." - "If A is a proper subset of B, or B is a proper subset of A, then comparison stops." - { "Next, the metaclasses of A and B are compared, with intrinsic meta-class order, from most-specific to least-specific:" - { $list - "Built-in classes and tuple classes" - "Predicate classes" - "Union classes" - "Mixin classes" - } - "If this yields an unambiguous answer, comparison stops." - } - "If the metaclasses of A and B occupy the same position in the order, then the vocabularies of A and B are compared lexicographically. If this yields an unambiguous answer, comparison stops." - "If A and B belong to the same vocabulary, their names are compared lexicographically. This must yield an unambiguous result, since if the names equal they must be the same class and this case was already handled in the first step." -} -"Some examples:" -{ $list - { { $link integer } " precedes " { $link number } " because it is a strict subset" } - { { $link number } " precedes " { $link sequence } " because the " { $vocab-link "math" } " vocabulary precedes the " { $vocab-link "sequences" } " vocabulary" } - { { $link crc32 } " precedes " { $link checksum } ", even if it were the only instance, because " { $link crc32 } " is a singleton class which is more specific than a mixin class" } + "Built-in classes and tuple classes" + "Predicate classes" + "Union classes" + "Mixin classes" } +"This means that in the above example, the generic word with methods on a mixin and its sole instance will always call the method for the sole instance, since it is more specific than a mixin class." +$nl +"The second problem is resolved with another tie-breaker. When performing the topological sort of classes, if there are multiple candidates at any given step of the sort, lexicographical order on the class name is used." +$nl "Operations:" -{ $subsection class<=> } +{ $subsection class< } { $subsection sort-classes } "Metaclass order:" { $subsection rank-class } ; @@ -72,8 +61,6 @@ HELP: sort-classes { $values { "seq" "a sequence of class" } { "newseq" "a new seqence of classes" } } { $description "Outputs a linear sort of a sequence of classes. Larger classes come before their subclasses." } ; -{ sort-classes class<=> } related-words - HELP: class-or { $values { "first" class } { "second" class } { "class" class } } { $description "Outputs the smallest anonymous class containing both " { $snippet "class1" } " and " { $snippet "class2" } "." } ; @@ -89,7 +76,3 @@ HELP: classes-intersect? HELP: min-class { $values { "class" class } { "seq" "a sequence of class words" } { "class/f" "a class word or " { $link f } } } { $description "If all classes in " { $snippet "seq" } " that intersect " { $snippet "class" } " are subtypes of " { $snippet "class" } ", outputs the last such element of " { $snippet "seq" } ". If any conditions fail to hold, outputs " { $link f } "." } ; - -HELP: class<=> -{ $values { "first" class } { "second" class } { "n" symbol } } -{ $description "Compares two classes with the class linearization order." } ; diff --git a/core/classes/algebra/algebra-tests.factor b/core/classes/algebra/algebra-tests.factor index 7387b8ae3a..dfe4a0fbc9 100755 --- a/core/classes/algebra/algebra-tests.factor +++ b/core/classes/algebra/algebra-tests.factor @@ -248,7 +248,16 @@ UNION: yyy xxx ; [ { yyy xxx } ] [ { xxx yyy } sort-classes ] unit-test [ { yyy xxx } ] [ { yyy xxx } sort-classes ] unit-test -[ { number integer ratio } ] [ { ratio number integer } sort-classes ] unit-test +[ { number ratio integer } ] [ { ratio number integer } sort-classes ] unit-test [ { sequence number ratio } ] [ { ratio number sequence } sort-classes ] unit-test -[ +lt+ ] [ \ real sequence class<=> ] unit-test +TUPLE: xa ; +TUPLE: xb ; +TUPLE: xc < xa ; +TUPLE: xd < xb ; +TUPLE: xe ; +TUPLE: xf < xb ; +TUPLE: xg < xb ; +TUPLE: xh < xb ; + +[ t ] [ { xa xb xc xd xe xf xg xh } sort-classes dup sort-classes = ] unit-test diff --git a/core/classes/algebra/algebra.factor b/core/classes/algebra/algebra.factor index 8c910a1f8c..4160f4e9d2 100755 --- a/core/classes/algebra/algebra.factor +++ b/core/classes/algebra/algebra.factor @@ -187,31 +187,15 @@ C: anonymous-complement [ [ rank-class ] bi@ < ] } cond ; -: class-tie-breaker ( first second -- n ) - 2dup [ rank-class ] compare { - { +lt+ [ 2drop +lt+ ] } - { +gt+ [ 2drop +gt+ ] } - { +eq+ [ <=> ] } - } case ; - -: (class<=>) ( first second -- n ) - { - { [ 2dup class<= ] [ - 2dup swap class<= - [ class-tie-breaker ] [ 2drop +lt+ ] if - ] } - { [ 2dup swap class<= ] [ - 2dup class<= - [ class-tie-breaker ] [ 2drop +gt+ ] if - ] } - [ class-tie-breaker ] - } cond ; - -: class<=> ( first second -- n ) - class<=>-cache get [ (class<=>) ] 2cache ; +: largest-class ( seq -- n elt ) + dup [ [ class< ] with contains? not ] curry find-last + [ "Topological sort failed" throw ] unless* ; : sort-classes ( seq -- newseq ) - [ class<=> invert-comparison ] sort ; + [ [ word-name ] compare ] sort >vector + [ dup empty? not ] + [ dup largest-class >r over delete-nth r> ] + [ ] unfold nip ; : min-class ( class seq -- class/f ) over [ classes-intersect? ] curry filter diff --git a/core/classes/classes.factor b/core/classes/classes.factor index 53840c0027..594b2005b8 100755 --- a/core/classes/classes.factor +++ b/core/classes/classes.factor @@ -6,7 +6,6 @@ quotations combinators sorting effects graphs vocabs ; IN: classes SYMBOL: class<=-cache -SYMBOL: class<=>-cache SYMBOL: class-not-cache SYMBOL: classes-intersect-cache SYMBOL: class-and-cache @@ -14,7 +13,6 @@ SYMBOL: class-or-cache : init-caches ( -- ) H{ } clone class<=-cache set - H{ } clone class<=>-cache set H{ } clone class-not-cache set H{ } clone classes-intersect-cache set H{ } clone class-and-cache set @@ -22,7 +20,6 @@ SYMBOL: class-or-cache : reset-caches ( -- ) class<=-cache get clear-assoc - class<=>-cache get clear-assoc class-not-cache get clear-assoc classes-intersect-cache get clear-assoc class-and-cache get clear-assoc diff --git a/core/math/order/order-docs.factor b/core/math/order/order-docs.factor index 98ff1920fa..23ea1058ad 100644 --- a/core/math/order/order-docs.factor +++ b/core/math/order/order-docs.factor @@ -25,8 +25,8 @@ HELP: +gt+ { $description "Returned by " { $link <=> } " when the first object is strictly greater than the second object." } ; HELP: invert-comparison -{ $values { "symbol" "a comparison symbol, +lt+, +eq+, or +gt+" } - { "new-symbol" "a comparison symbol, +lt+, +eq+, or +gt+" } } +{ $values { "symbol" symbol } + { "new-symbol" symbol } } { $description "Invert the comparison symbol returned by " { $link <=> } ". The output for the symbol " { $snippet "+eq+" } " is itself." } { $examples { $example "USING: math.order prettyprint ;" "+lt+ invert-comparison ." "+gt+" } } ; diff --git a/core/optimizer/def-use/def-use-tests.factor b/core/optimizer/def-use/def-use-tests.factor index ef829da9f2..f49ab7fcba 100755 --- a/core/optimizer/def-use/def-use-tests.factor +++ b/core/optimizer/def-use/def-use-tests.factor @@ -1,6 +1,6 @@ IN: optimizer.def-use.tests USING: inference inference.dataflow optimizer optimizer.def-use -namespaces assocs kernel sequences math tools.test words ; +namespaces assocs kernel sequences math tools.test words sets ; [ 3 { 1 1 1 } ] [ [ 1 2 3 ] dataflow compute-def-use drop diff --git a/extra/bank/bank.factor b/extra/bank/bank.factor index 35d1337afc..abe3250ecf 100644 --- a/extra/bank/bank.factor +++ b/extra/bank/bank.factor @@ -26,8 +26,6 @@ C: transaction : daily-rate>> ( account date -- rate ) [ interest-rate>> ] dip daily-rate ; -: before? ( date date -- ? ) <=> 0 < ; - : transactions-on-date ( account date -- transactions ) [ before? ] curry filter ; diff --git a/extra/html/html.factor b/extra/html/html.factor index f0ae424760..7a0fa17c9a 100755 --- a/extra/html/html.factor +++ b/extra/html/html.factor @@ -225,13 +225,13 @@ M: html-stream stream-nl ( stream -- ) : vertical-layout ( list -- ) #! Given a list of HTML components, arrange them vertically. - +
[ ] each
call
; : horizontal-layout ( list -- ) #! Given a list of HTML components, arrange them horizontally. - +
[ ] each
call
; @@ -246,8 +246,8 @@ M: html-stream stream-nl ( stream -- ) : simple-page ( title quot -- ) #! Call the quotation, with all output going to the #! body of an html page with the given title. - - swap write + + swap write call ; @@ -255,10 +255,13 @@ M: html-stream stream-nl ( stream -- ) #! Call the quotation, with all output going to the #! body of an html page with the given title. stylesheet-quot #! is called to generate the required stylesheet. - - - rot write - swap call - + + + rot write + swap call + call ; + +: render-error ( message -- ) + escape-string write ; diff --git a/extra/http/http-tests.factor b/extra/http/http-tests.factor index 831becd264..76c48d38f1 100755 --- a/extra/http/http-tests.factor +++ b/extra/http/http-tests.factor @@ -30,6 +30,7 @@ IN: http.tests [ H{ { "a" { "b" "c" } } } ] [ "a=b&a=c" query>assoc ] unit-test +[ "a=3" ] [ { { "a" 3 } } assoc>query ] unit-test : lf>crlf "\n" split "\r\n" join ; STRING: read-request-test-1 diff --git a/extra/http/http.factor b/extra/http/http.factor index 315250692b..98c1d8e74c 100755 --- a/extra/http/http.factor +++ b/extra/http/http.factor @@ -143,7 +143,7 @@ IN: http : assoc>query ( hash -- str ) [ { - { [ dup number? ] [ number>string ] } + { [ dup number? ] [ number>string 1array ] } { [ dup string? ] [ 1array ] } { [ dup sequence? ] [ ] } } cond diff --git a/extra/http/server/actions/actions.factor b/extra/http/server/actions/actions.factor index 6e1aac9627..2d73cb46a7 100755 --- a/extra/http/server/actions/actions.factor +++ b/extra/http/server/actions/actions.factor @@ -2,13 +2,20 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors sequences kernel assocs combinators http.server http.server.validators http hashtables namespaces -fry continuations locals ; +fry continuations locals boxes xml.entities html.elements io ; IN: http.server.actions -SYMBOL: +path+ - SYMBOL: params +SYMBOL: validation-message + +: render-validation-message ( -- ) + validation-message get value>> [ + + escape-string write + + ] when* ; + TUPLE: action init display submit get-params post-params ; : @@ -37,11 +44,16 @@ TUPLE: action init display submit get-params post-params ; : validation-failed ( -- * ) action get display>> call exit-with ; +: validation-failed-with ( string -- * ) + validation-message get >box + validation-failed ; + M: action call-responder* ( path action -- response ) '[ , [ CHAR: / = ] right-trim empty? [ , action set request get + validation-message set [ request-params params set ] [ method>> { diff --git a/extra/http/server/auth/admin/admin.xml b/extra/http/server/auth/admin/admin.xml index 1864c3c4bf..05817565ed 100644 --- a/extra/http/server/auth/admin/admin.xml +++ b/extra/http/server/auth/admin/admin.xml @@ -2,8 +2,6 @@ - -

diff --git a/extra/http/server/auth/admin/edit-user.xml b/extra/http/server/auth/admin/edit-user.xml index b8c235532b..9c0fe702bb 100644 --- a/extra/http/server/auth/admin/edit-user.xml +++ b/extra/http/server/auth/admin/edit-user.xml @@ -4,9 +4,7 @@ Edit User - - - + @@ -49,17 +47,10 @@

- - - passwords do not match - +

- - - - - + Delete diff --git a/extra/http/server/auth/admin/new-user.xml b/extra/http/server/auth/admin/new-user.xml index 072e0c95bd..2d67639985 100644 --- a/extra/http/server/auth/admin/new-user.xml +++ b/extra/http/server/auth/admin/new-user.xml @@ -42,14 +42,7 @@

- - - username taken - - - - passwords do not match - +

diff --git a/extra/http/server/auth/login/edit-profile.xml b/extra/http/server/auth/login/edit-profile.xml index 107dbba2b8..1eaf65fa07 100644 --- a/extra/http/server/auth/login/edit-profile.xml +++ b/extra/http/server/auth/login/edit-profile.xml @@ -62,14 +62,7 @@

- - - invalid password - - - - passwords do not match - +

diff --git a/extra/http/server/auth/login/login.factor b/extra/http/server/auth/login/login.factor index 28486f3362..9f1fe6fe77 100755 --- a/extra/http/server/auth/login/login.factor +++ b/extra/http/server/auth/login/login.factor @@ -30,8 +30,6 @@ http.server.validators ; IN: http.server.auth.login QUALIFIED: smtp -SYMBOL: login-failed? - TUPLE: login < dispatcher users checksum ; : users ( -- provider ) @@ -82,6 +80,8 @@ M: user-saver dispose username>> set-uid "$login" end-flow ; +: login-failed "invalid username or password" validation-failed-with ; + :: ( -- action ) [let | form [ ] | @@ -94,12 +94,8 @@ M: user-saver dispose form validate-form - "password" value "username" value check-login [ - successful-login - ] [ - login-failed? on - validation-failed - ] if* + "password" value "username" value check-login + [ successful-login ] [ login-failed ] if* ] >>submit ] ; @@ -121,14 +117,13 @@ M: user-saver dispose "email" add-field "captcha" add-field ; -SYMBOL: password-mismatch? -SYMBOL: user-exists? +: password-mismatch "passwords do not match" validation-failed-with ; + +: user-exists "username taken" validation-failed-with ; : same-password-twice ( -- ) - "new-password" value "verify-password" value = [ - password-mismatch? on - validation-failed - ] unless ; + "new-password" value "verify-password" value = + [ password-mismatch ] unless ; :: ( -- action ) [let | form [ ] | @@ -150,10 +145,7 @@ SYMBOL: user-exists? "email" value >>email H{ } clone >>profile - users new-user [ - user-exists? on - validation-failed - ] unless* + users new-user [ user-exists ] unless* successful-login @@ -201,7 +193,7 @@ SYMBOL: user-exists? same-password-twice "password" value uid check-login - [ login-failed? on validation-failed ] unless + [ login-failed ] unless "new-password" value >>encoded-password ] unless diff --git a/extra/http/server/auth/login/login.xml b/extra/http/server/auth/login/login.xml index 0524d0889f..d0a73a4d8b 100644 --- a/extra/http/server/auth/login/login.xml +++ b/extra/http/server/auth/login/login.xml @@ -23,10 +23,8 @@

+ - - invalid username or password -

diff --git a/extra/http/server/auth/login/recover-3.xml b/extra/http/server/auth/login/recover-3.xml index 61ef0aef86..6c60b257a8 100644 --- a/extra/http/server/auth/login/recover-3.xml +++ b/extra/http/server/auth/login/recover-3.xml @@ -32,10 +32,7 @@

- - - passwords do not match - +

diff --git a/extra/http/server/auth/login/register.xml b/extra/http/server/auth/login/register.xml index 19917002b5..9b45a7f087 100644 --- a/extra/http/server/auth/login/register.xml +++ b/extra/http/server/auth/login/register.xml @@ -63,14 +63,7 @@

- - - username taken - - - - passwords do not match - +

diff --git a/extra/http/server/components/code/code.factor b/extra/http/server/components/code/code.factor index 8bf07700e8..19fc8c5ca8 100644 --- a/extra/http/server/components/code/code.factor +++ b/extra/http/server/components/code/code.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: splitting kernel io sequences xmode.code2html accessors -http.server.components xml.entities ; +http.server.components html xml.entities ; IN: http.server.components.code TUPLE: code-renderer < text-renderer mode ; @@ -11,7 +11,9 @@ TUPLE: code-renderer < text-renderer mode ; swap >>mode ; M: code-renderer render-view* - [ string-lines ] [ mode>> value ] bi* htmlize-lines ; + [ + [ string-lines ] [ mode>> value ] bi* htmlize-lines + ] with-html-stream ; : ( id mode -- component ) swap diff --git a/extra/http/server/components/components.factor b/extra/http/server/components/components.factor index c0bac1fb99..7f2a5a9ce1 100755 --- a/extra/http/server/components/components.factor +++ b/extra/http/server/components/components.factor @@ -3,7 +3,7 @@ USING: accessors namespaces kernel io math.parser assocs classes words classes.tuple arrays sequences splitting mirrors hashtables fry locals combinators continuations math -calendar.format html.elements xml.entities +calendar.format html html.elements xml.entities http.server.validators ; IN: http.server.components @@ -24,9 +24,6 @@ M: field render-view* M: field render-edit* > =type =name =value input/> ; -: render-error ( message -- ) - escape-string write ; - TUPLE: hidden < field ; : hidden ( -- renderer ) T{ hidden f "hidden" } ; inline diff --git a/extra/http/server/templating/chloe/chloe.factor b/extra/http/server/templating/chloe/chloe.factor index a8a456cdb2..c3d93f5909 100644 --- a/extra/http/server/templating/chloe/chloe.factor +++ b/extra/http/server/templating/chloe/chloe.factor @@ -1,10 +1,14 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel sequences combinators kernel namespaces classes.tuple assocs splitting words arrays memoize -io io.files io.encodings.utf8 html.elements unicode.case -tuple-syntax xml xml.data xml.writer xml.utilities +io io.files io.encodings.utf8 io.streams.string +unicode.case tuple-syntax html html.elements +multiline xml xml.data xml.writer xml.utilities http.server http.server.auth http.server.flows +http.server.actions http.server.components http.server.sessions http.server.templating @@ -21,7 +25,10 @@ DEFER: process-template : chloe-ns "http://factorcode.org/chloe/1.0" ; inline -: filter-chloe-attrs ( assoc -- assoc' ) +: chloe-attrs-only ( assoc -- assoc' ) + [ drop name-url chloe-ns = ] assoc-filter ; + +: non-chloe-attrs-only ( assoc -- assoc' ) [ drop name-url chloe-ns = not ] assoc-filter ; : chloe-tag? ( tag -- ? ) @@ -45,6 +52,12 @@ MEMO: chloe-name ( string -- name ) : optional-attr ( tag name -- value ) chloe-name swap at ; +: children>string ( tag -- string ) + [ [ process-template ] each ] with-string-writer ; + +: title-tag ( tag -- ) + children>string set-title ; + : write-title-tag ( tag -- ) drop "head" tags get member? "title" tags get member? not and @@ -131,16 +144,20 @@ MEMO: chloe-name ( string -- name ) : form-start-tag ( tag -- ) [ -
- hidden-form-field + [ + + ] [ + hidden-form-field + "for" optional-attr [ component render-edit ] when* + ] bi ] with-scope ; : form-tag ( tag -- ) @@ -149,6 +166,26 @@ MEMO: chloe-name ( string -- name ) [ drop ] tri ; +DEFER: process-chloe-tag + +STRING: button-tag-markup + + + +; + +: add-tag-attrs ( attrs tag -- ) + tag-attrs swap update ; + +: button-tag ( tag -- ) + button-tag-markup string>xml delegate + { + [ >r tag-attrs chloe-attrs-only r> add-tag-attrs ] + [ >r tag-attrs non-chloe-attrs-only r> "button" tag-named add-tag-attrs ] + [ >r children>string 1array r> "button" tag-named set-tag-children ] + [ nip ] + } 2cleave process-chloe-tag ; + : attr>word ( value -- word/f ) dup ":" split1 swap lookup [ ] [ "No such word: " swap append throw ] ?if ; @@ -159,23 +196,25 @@ MEMO: chloe-name ( string -- name ) ] unless ; : if-satisfied? ( tag -- ? ) + t swap { - [ "code" optional-attr [ attr>word execute ] [ t ] if* ] - [ "var" optional-attr [ attr>var get ] [ t ] if* ] - [ "svar" optional-attr [ attr>var sget ] [ t ] if* ] - [ "uvar" optional-attr [ attr>var uget ] [ t ] if* ] - } cleave 4array [ ] all? ; + [ "code" optional-attr [ attr>word execute and ] when* ] + [ "var" optional-attr [ attr>var get and ] when* ] + [ "svar" optional-attr [ attr>var sget and ] when* ] + [ "uvar" optional-attr [ attr>var uget and ] when* ] + [ "value" optional-attr [ value and ] when* ] + } cleave ; : if-tag ( tag -- ) dup if-satisfied? [ process-tag-children ] [ drop ] if ; -: error-tag ( tag -- ) +: error-message-tag ( tag -- ) children>string render-error ; : process-chloe-tag ( tag -- ) dup name-tag { { "chloe" [ [ process-template ] each ] } - { "title" [ children>string set-title ] } + { "title" [ title-tag ] } { "write-title" [ write-title-tag ] } { "style" [ style-tag ] } { "write-style" [ write-style-tag ] } @@ -186,7 +225,9 @@ MEMO: chloe-name ( string -- name ) { "summary" [ summary-tag ] } { "a" [ a-tag ] } { "form" [ form-tag ] } - { "error" [ error-tag ] } + { "button" [ button-tag ] } + { "error-message" [ error-message-tag ] } + { "validation-message" [ drop render-validation-message ] } { "if" [ if-tag ] } { "comment" [ drop ] } { "call-next-template" [ drop call-next-template ] } diff --git a/extra/monads/authors.txt b/extra/monads/authors.txt new file mode 100644 index 0000000000..1901f27a24 --- /dev/null +++ b/extra/monads/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/extra/monads/monads-tests.factor b/extra/monads/monads-tests.factor new file mode 100644 index 0000000000..52cdc47ac6 --- /dev/null +++ b/extra/monads/monads-tests.factor @@ -0,0 +1,128 @@ +USING: tools.test monads math kernel sequences lazy-lists promises ; +IN: monads.tests + +[ 5 ] [ 1 identity-monad return [ 4 + ] fmap run-identity ] unit-test +[ "OH HAI" identity-monad fail ] must-fail + +[ 666 ] [ + 111 just [ 6 * ] fmap [ ] [ "OOPS" throw ] if-maybe +] unit-test + +[ nothing ] [ + 111 just [ maybe-monad fail ] bind +] unit-test + +[ 100 ] [ + 5 either-monad return [ 10 * ] [ 20 * ] if-either +] unit-test + +[ T{ left f "OOPS" } ] [ + 5 either-monad return >>= [ drop "OOPS" either-monad fail ] swap call +] unit-test + +[ { 10 20 30 } ] [ + { 1 2 3 } [ 10 * ] fmap +] unit-test + +[ { } ] [ + { 1 2 3 } [ drop "OOPS" array-monad fail ] bind +] unit-test + +[ 5 ] [ + 5 state-monad return "initial state" run-st +] unit-test + +[ 8 ] [ + 5 state-monad return [ 3 + state-monad return ] bind + "initial state" run-st +] unit-test + +[ 8 ] [ + 5 state-monad return >>= + [ 3 + state-monad return ] swap call + "initial state" run-st +] unit-test + +[ 11 ] [ + f state-monad return >>= + [ drop get-st ] swap call + 11 run-st +] unit-test + +[ 15 ] [ + f state-monad return + [ drop get-st ] bind + [ 4 + put-st ] bind + [ drop get-st ] bind + 11 run-st +] unit-test + +[ 15 ] [ + { + [ f return-st ] + [ drop get-st ] + [ 4 + put-st ] + [ drop get-st ] + } do + 11 run-st +] unit-test + +[ nothing ] [ + { + [ "hi" just ] + [ " bye" append just ] + [ drop nothing ] + [ reverse just ] + } do +] unit-test + +LAZY: nats-from ( n -- list ) + dup 1+ nats-from cons ; + +: nats 0 nats-from ; + +[ 3 ] [ + { + [ nats ] + [ dup 3 = [ list-monad return ] [ list-monad fail ] if ] + } do car +] unit-test + +[ 9/11 ] [ + { + [ ask ] + } do 9/11 run-reader +] unit-test + +[ 8 ] [ + { + [ ask ] + [ 3 + reader-monad return ] + } do + 5 run-reader +] unit-test + +[ 6 ] [ + f reader-monad return [ drop ask ] bind [ 1 + ] local 5 run-reader +] unit-test + +[ f { 1 2 3 } ] [ + 5 writer-monad return + [ drop { 1 2 3 } tell ] bind + run-writer +] unit-test + +[ T{ identity f 7 } ] +[ + 4 identity-monad return + [ 3 + ] identity-monad return + identity-monad apply +] unit-test + +[ nothing ] [ + 5 just nothing maybe-monad apply +] unit-test + +[ T{ just f 15 } ] [ + 5 just [ 10 + ] just maybe-monad apply +] unit-test diff --git a/extra/monads/monads.factor b/extra/monads/monads.factor new file mode 100644 index 0000000000..0f4138c985 --- /dev/null +++ b/extra/monads/monads.factor @@ -0,0 +1,192 @@ +! Copyright (C) 2008 Slava Pestov +! See http://factorcode.org/license.txt for BSD license. +USING: arrays kernel sequences sequences.deep splitting +accessors fry locals combinators namespaces lazy-lists +shuffle ; +IN: monads + +! Functors +GENERIC# fmap 1 ( functor quot -- functor' ) inline + +! Monads + +! Mixin type for monad singleton classes, used for return/fail only +MIXIN: monad + +GENERIC: monad-of ( mvalue -- singleton ) +GENERIC: return ( string singleton -- mvalue ) +GENERIC: fail ( value singleton -- mvalue ) +GENERIC: >>= ( mvalue -- quot ) + +M: monad return monad-of return ; +M: monad fail monad-of fail ; + +: bind ( mvalue quot -- mvalue' ) swap >>= call ; +: >> ( mvalue k -- mvalue' ) '[ drop , ] bind ; + +:: lift-m2 ( m1 m2 f monad -- m3 ) + m1 [| x1 | m2 [| x2 | x1 x2 f monad return ] bind ] bind ; + +:: apply ( mvalue mquot monad -- result ) + mvalue [| value | + mquot [| quot | + value quot call monad return + ] bind + ] bind ; + +M: monad fmap over '[ @ , return ] bind ; + +! 'do' notation +: do ( quots -- result ) unclip dip [ bind ] each ; + +! Identity +SINGLETON: identity-monad +INSTANCE: identity-monad monad + +TUPLE: identity value ; +INSTANCE: identity monad + +M: identity monad-of drop identity-monad ; + +M: identity-monad return drop identity boa ; +M: identity-monad fail "Fail" throw ; + +M: identity >>= value>> '[ , _ call ] ; + +: run-identity ( identity -- value ) value>> ; + +! Maybe +SINGLETON: maybe-monad +INSTANCE: maybe-monad monad + +SINGLETON: nothing + +TUPLE: just value ; +: just \ just boa ; + +UNION: maybe just nothing ; +INSTANCE: maybe monad + +M: maybe monad-of drop maybe-monad ; + +M: maybe-monad return drop just ; +M: maybe-monad fail 2drop nothing ; + +M: nothing >>= '[ drop , ] ; +M: just >>= value>> '[ , _ call ] ; + +: if-maybe ( maybe just-quot nothing-quot -- ) + pick nothing? [ 2nip call ] [ drop [ value>> ] dip call ] if ; inline + +! Either +SINGLETON: either-monad +INSTANCE: either-monad monad + +TUPLE: left value ; +: left \ left boa ; + +TUPLE: right value ; +: right \ right boa ; + +UNION: either left right ; +INSTANCE: either monad + +M: either monad-of drop either-monad ; + +M: either-monad return drop right ; +M: either-monad fail drop left ; + +M: left >>= '[ drop , ] ; +M: right >>= value>> '[ , _ call ] ; + +: if-either ( value left-quot right-quot -- ) + [ [ value>> ] [ left? ] bi ] 2dip if ; inline + +! Arrays +SINGLETON: array-monad +INSTANCE: array-monad monad +INSTANCE: array monad + +M: array-monad return drop 1array ; +M: array-monad fail 2drop { } ; + +M: array monad-of drop array-monad ; + +M: array >>= '[ , _ map concat ] ; + +! List +SINGLETON: list-monad +INSTANCE: list-monad monad +INSTANCE: list monad + +M: list-monad return drop 1list ; +M: list-monad fail 2drop nil ; + +M: list monad-of drop list-monad ; + +M: list >>= '[ , _ lmap lconcat ] ; + +! State +SINGLETON: state-monad +INSTANCE: state-monad monad + +TUPLE: state quot ; +: state \ state boa ; + +INSTANCE: state monad + +M: state monad-of drop state-monad ; + +M: state-monad return drop '[ , 2array ] state ; +M: state-monad fail "Fail" throw ; + +: mcall quot>> call ; + +M: state >>= '[ , _ '[ , mcall first2 @ mcall ] state ] ; + +: get-st ( -- state ) [ dup 2array ] state ; +: put-st ( value -- state ) '[ drop , f 2array ] state ; + +: run-st ( state initial -- ) swap mcall second ; + +: return-st state-monad return ; + +! Reader +SINGLETON: reader-monad +INSTANCE: reader-monad monad + +TUPLE: reader quot ; +: reader \ reader boa ; +INSTANCE: reader monad + +M: reader monad-of drop reader-monad ; + +M: reader-monad return drop '[ drop , ] reader ; +M: reader-monad fail "Fail" throw ; + +M: reader >>= '[ , _ '[ dup , mcall @ mcall ] reader ] ; + +: run-reader ( reader env -- ) swap mcall ; + +: ask ( -- reader ) [ ] reader ; +: local ( reader quot -- reader' ) swap '[ @ , mcall ] reader ; + +! Writer +SINGLETON: writer-monad +INSTANCE: writer-monad monad + +TUPLE: writer value log ; +: writer \ writer boa ; + +M: writer monad-of drop writer-monad ; + +M: writer-monad return drop { } writer ; +M: writer-monad fail "Fail" throw ; + +: run-writer ( writer -- value log ) [ value>> ] [ log>> ] bi ; + +M: writer >>= '[ , run-writer _ '[ @ run-writer ] dip append writer ] ; + +: pass ( writer -- writer' ) run-writer [ first2 ] dip swap call writer ; +: listen ( writer -- writer' ) run-writer [ 2array ] keep writer ; +: tell ( seq -- writer ) f swap writer ; diff --git a/extra/monads/summary.txt b/extra/monads/summary.txt new file mode 100644 index 0000000000..359722ce04 --- /dev/null +++ b/extra/monads/summary.txt @@ -0,0 +1 @@ +Haskell-style monads diff --git a/extra/monads/tags.txt b/extra/monads/tags.txt new file mode 100644 index 0000000000..f4274299b1 --- /dev/null +++ b/extra/monads/tags.txt @@ -0,0 +1 @@ +extensions diff --git a/extra/shuffle/shuffle.factor b/extra/shuffle/shuffle.factor index 33587bb7fa..89522d1f76 100644 --- a/extra/shuffle/shuffle.factor +++ b/extra/shuffle/shuffle.factor @@ -5,6 +5,8 @@ USING: kernel sequences namespaces math inference.transforms IN: shuffle +: 2dip -rot 2slip ; inline + MACRO: npick ( n -- ) 1- dup saver [ dup ] rot [ r> swap ] n*quot 3append ; MACRO: ndup ( n -- ) dup [ npick ] curry n*quot ; diff --git a/extra/tools/deploy/shaker/shaker.factor b/extra/tools/deploy/shaker/shaker.factor index 1ad9957cc9..d507357590 100755 --- a/extra/tools/deploy/shaker/shaker.factor +++ b/extra/tools/deploy/shaker/shaker.factor @@ -145,7 +145,6 @@ IN: tools.deploy.shaker classes:class-not-cache classes:class-or-cache classes:class<=-cache - classes:class<=>-cache classes:classes-intersect-cache classes:update-map command-line:main-vocab-hook diff --git a/extra/webapps/factor-website/page.css b/extra/webapps/factor-website/page.css index 9846e7b20c..55721d7bef 100644 --- a/extra/webapps/factor-website/page.css +++ b/extra/webapps/factor-website/page.css @@ -43,6 +43,13 @@ a:hover, .link:hover { border: 1px dashed #ccc; background-color: #f5f5f5; padding: 5px; - font-size: 150%; - color: #000000; + color: #000; +} + +.description p:first-child { + margin-top: 0px; +} + +.description p:last-child { + margin-bottom: 0px; } diff --git a/extra/webapps/pastebin/annotation.xml b/extra/webapps/pastebin/annotation.xml index e5a95d8908..d5b4ea8d3a 100644 --- a/extra/webapps/pastebin/annotation.xml +++ b/extra/webapps/pastebin/annotation.xml @@ -10,14 +10,8 @@
Date:
-
- -
+
- - - - - + Delete Annotation
diff --git a/extra/webapps/pastebin/new-annotation.xml b/extra/webapps/pastebin/new-annotation.xml index ad7152d209..5d18860977 100644 --- a/extra/webapps/pastebin/new-annotation.xml +++ b/extra/webapps/pastebin/new-annotation.xml @@ -4,8 +4,7 @@ New Annotation - - + diff --git a/extra/webapps/pastebin/paste-summary.xml b/extra/webapps/pastebin/paste-summary.xml index eca46e254d..c751b110c0 100644 --- a/extra/webapps/pastebin/paste-summary.xml +++ b/extra/webapps/pastebin/paste-summary.xml @@ -3,7 +3,7 @@ - + diff --git a/extra/webapps/pastebin/paste.xml b/extra/webapps/pastebin/paste.xml index 9db60bfcc3..9141ee4ef1 100644 --- a/extra/webapps/pastebin/paste.xml +++ b/extra/webapps/pastebin/paste.xml @@ -2,9 +2,7 @@ - Pastebin - -

Paste:

+ Paste:
Summary:
@@ -14,10 +12,7 @@
- - - - + Delete Paste | Annotate diff --git a/extra/webapps/pastebin/pastebin.factor b/extra/webapps/pastebin/pastebin.factor index 144900d6ec..a18eb8147c 100644 --- a/extra/webapps/pastebin/pastebin.factor +++ b/extra/webapps/pastebin/pastebin.factor @@ -207,12 +207,11 @@ annotation "ANNOTATION" :: ( ctor next -- action ) - { { "id" [ v-number ] } { "aid" [ v-number ] } } >>post-params + { { "aid" [ v-number ] } } >>post-params [ - "id" get "aid" get ctor call delete-tuples - - "id" get next + f "aid" get ctor call select-tuple + [ delete-tuples ] [ id>> next ] bi ] >>submit ; :: ( form ctor next -- action ) @@ -247,7 +246,7 @@ can-delete-pastes? define-capability "feed.xml" add-responder [ ] "view-paste" add-responder [ ] "$pastebin/list" { can-delete-pastes? } "delete-paste" add-responder - [ ] "$pastebin/view-paste" { can-delete-pastes? } "delete-annotation" add-responder + [ ] "$pastebin/view-paste" { can-delete-pastes? } "delete-annotation" add-responder [ ] "$pastebin/view-paste" add-responder [ now >>date ] "$pastebin/view-paste" "new-paste" add-responder [ now >>date ] "$pastebin/view-paste" "annotate" add-responder diff --git a/extra/webapps/pastebin/pastebin.xml b/extra/webapps/pastebin/pastebin.xml index 461a7be384..7ca4c95f8e 100644 --- a/extra/webapps/pastebin/pastebin.xml +++ b/extra/webapps/pastebin/pastebin.xml @@ -11,15 +11,13 @@ | New Paste | Atom Feed - + | Edit Profile - - | - + | Logout diff --git a/extra/webapps/planet/edit-blog.xml b/extra/webapps/planet/edit-blog.xml index b2eab2b0b4..ebfccc47de 100644 --- a/extra/webapps/planet/edit-blog.xml +++ b/extra/webapps/planet/edit-blog.xml @@ -4,9 +4,7 @@ Edit Blog - - - +
Author:
@@ -31,8 +29,5 @@ - - - - + Delete diff --git a/extra/webapps/planet/planet.xml b/extra/webapps/planet/planet.xml index 7f2b034366..29609e12ba 100644 --- a/extra/webapps/planet/planet.xml +++ b/extra/webapps/planet/planet.xml @@ -9,14 +9,12 @@ | Atom Feed | Admin - + | Edit Profile - - | - + | Logout diff --git a/extra/webapps/todo/edit-todo.xml b/extra/webapps/todo/edit-todo.xml index 9b7e9e667a..e1d4c40e23 100644 --- a/extra/webapps/todo/edit-todo.xml +++ b/extra/webapps/todo/edit-todo.xml @@ -4,9 +4,7 @@ Edit Item - - - +
@@ -16,11 +14,12 @@ - View - | - - - - + + + View + | + Delete + + diff --git a/extra/webapps/todo/todo.xml b/extra/webapps/todo/todo.xml index 3e6d3cfd44..651e29d867 100644 --- a/extra/webapps/todo/todo.xml +++ b/extra/webapps/todo/todo.xml @@ -12,9 +12,7 @@ | Edit Profile - - | - + Logout

diff --git a/extra/webapps/todo/view-todo.xml b/extra/webapps/todo/view-todo.xml index 1bd73f48e1..8c90ba9056 100644 --- a/extra/webapps/todo/view-todo.xml +++ b/extra/webapps/todo/view-todo.xml @@ -15,9 +15,6 @@ Edit | - - - - + Delete diff --git a/misc/Factor.tmbundle/Syntaxes/HTML (Factor).tmLanguage b/misc/Factor.tmbundle/Syntaxes/HTML (Factor).tmLanguage index 03394b933c..1bf9a17aa6 100644 --- a/misc/Factor.tmbundle/Syntaxes/HTML (Factor).tmLanguage +++ b/misc/Factor.tmbundle/Syntaxes/HTML (Factor).tmLanguage @@ -29,7 +29,7 @@ begin<%\send - \s%> + (?<=\s)%>namesource.factor.embedded.htmlpatterns
Summary:
Priority: