2008-05-03 05:44:02 -04:00
|
|
|
! Copyright (C) 2008 Slava Pestov
|
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
|
|
USING: arrays kernel sequences sequences.deep splitting
|
2008-06-03 04:27:25 -04:00
|
|
|
accessors fry locals combinators namespaces lists lists.lazy
|
2008-05-03 05:44:02 -04:00
|
|
|
shuffle ;
|
|
|
|
IN: monads
|
|
|
|
|
|
|
|
! Functors
|
2017-06-01 14:58:58 -04:00
|
|
|
GENERIC#: fmap 1 ( functor quot -- functor' )
|
|
|
|
GENERIC#: <$ 1 ( functor quot -- functor' )
|
|
|
|
GENERIC#: $> 1 ( functor quot -- functor' )
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! Monads
|
|
|
|
|
|
|
|
! Mixin type for monad singleton classes, used for return/fail only
|
|
|
|
MIXIN: monad
|
|
|
|
|
|
|
|
GENERIC: monad-of ( mvalue -- singleton )
|
2008-06-09 03:14:14 -04:00
|
|
|
GENERIC: return ( value singleton -- mvalue )
|
2008-05-03 05:44:02 -04:00
|
|
|
GENERIC: fail ( value singleton -- mvalue )
|
|
|
|
GENERIC: >>= ( mvalue -- quot )
|
|
|
|
|
|
|
|
M: monad return monad-of return ;
|
|
|
|
M: monad fail monad-of fail ;
|
|
|
|
|
2009-03-16 21:11:36 -04:00
|
|
|
: bind ( mvalue quot -- mvalue' ) swap >>= call( quot -- mvalue ) ;
|
2009-05-24 10:36:24 -04:00
|
|
|
: bind* ( mvalue quot -- mvalue' ) '[ drop @ ] bind ;
|
2008-09-10 23:11:40 -04:00
|
|
|
: >> ( mvalue k -- mvalue' ) '[ drop _ ] bind ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
:: 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 |
|
2009-03-16 21:11:36 -04:00
|
|
|
value quot call( value -- mvalue ) monad return
|
2008-05-03 05:44:02 -04:00
|
|
|
] bind
|
|
|
|
] bind ;
|
|
|
|
|
2008-09-10 23:11:40 -04:00
|
|
|
M: monad fmap over '[ @ _ return ] bind ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! 'do' notation
|
2009-03-16 21:11:36 -04:00
|
|
|
: do ( quots -- result ) unclip [ call( -- mvalue ) ] curry dip [ bind ] each ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! 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 ;
|
|
|
|
|
2009-03-16 21:11:36 -04:00
|
|
|
M: identity >>= value>> '[ _ swap call( x -- y ) ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
: run-identity ( identity -- value ) value>> ;
|
|
|
|
|
|
|
|
! Maybe
|
|
|
|
SINGLETON: maybe-monad
|
|
|
|
INSTANCE: maybe-monad monad
|
|
|
|
|
|
|
|
SINGLETON: nothing
|
|
|
|
|
|
|
|
TUPLE: just value ;
|
2013-03-24 04:38:25 -04:00
|
|
|
C: <just> just
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
UNION: maybe just nothing ;
|
|
|
|
INSTANCE: maybe monad
|
|
|
|
|
|
|
|
M: maybe monad-of drop maybe-monad ;
|
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: maybe-monad return drop <just> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
M: maybe-monad fail 2drop nothing ;
|
|
|
|
|
2008-09-10 23:11:40 -04:00
|
|
|
M: nothing >>= '[ drop _ ] ;
|
2009-03-16 21:11:36 -04:00
|
|
|
M: just >>= value>> '[ _ swap call( x -- y ) ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
: 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 ;
|
2013-03-24 04:38:25 -04:00
|
|
|
C: <left> left
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
TUPLE: right value ;
|
2013-03-24 04:38:25 -04:00
|
|
|
C: <right> right
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
UNION: either left right ;
|
|
|
|
INSTANCE: either monad
|
|
|
|
|
|
|
|
M: either monad-of drop either-monad ;
|
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: either-monad return drop <right> ;
|
|
|
|
M: either-monad fail drop <left> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2008-09-10 23:11:40 -04:00
|
|
|
M: left >>= '[ drop _ ] ;
|
2009-03-16 21:11:36 -04:00
|
|
|
M: right >>= value>> '[ _ swap call( x -- y ) ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
: 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 ;
|
|
|
|
|
2008-09-10 23:11:40 -04:00
|
|
|
M: array >>= '[ _ swap map concat ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! 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 ;
|
|
|
|
|
2016-04-17 16:08:32 -04:00
|
|
|
M: list >>= '[ _ swap lmap-lazy lconcat ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! State
|
|
|
|
SINGLETON: state-monad
|
|
|
|
INSTANCE: state-monad monad
|
|
|
|
|
|
|
|
TUPLE: state quot ;
|
2013-03-24 04:38:25 -04:00
|
|
|
C: <state> state
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
INSTANCE: state monad
|
|
|
|
|
|
|
|
M: state monad-of drop state-monad ;
|
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: state-monad return drop '[ _ 2array ] <state> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
M: state-monad fail "Fail" throw ;
|
|
|
|
|
2009-03-16 21:11:36 -04:00
|
|
|
: mcall ( x state -- y ) quot>> call( x -- y ) ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: state >>= '[ _ swap '[ _ mcall first2 @ mcall ] <state> ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
: get-st ( -- state ) [ dup 2array ] <state> ;
|
|
|
|
: put-st ( value -- state ) '[ drop _ f 2array ] <state> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2009-03-16 21:11:36 -04:00
|
|
|
: run-st ( state initial -- value ) swap mcall second ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2008-06-09 03:14:14 -04:00
|
|
|
: return-st ( value -- mvalue ) state-monad return ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! Reader
|
|
|
|
SINGLETON: reader-monad
|
|
|
|
INSTANCE: reader-monad monad
|
|
|
|
|
|
|
|
TUPLE: reader quot ;
|
2013-03-24 04:38:25 -04:00
|
|
|
C: <reader> reader
|
2008-05-03 05:44:02 -04:00
|
|
|
INSTANCE: reader monad
|
|
|
|
|
|
|
|
M: reader monad-of drop reader-monad ;
|
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: reader-monad return drop '[ drop _ ] <reader> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
M: reader-monad fail "Fail" throw ;
|
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: reader >>= '[ _ swap '[ dup _ mcall @ mcall ] <reader> ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2009-03-16 21:11:36 -04:00
|
|
|
: run-reader ( reader env -- value ) swap quot>> call( env -- value ) ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
: ask ( -- reader ) [ ] <reader> ;
|
|
|
|
: local ( reader quot -- reader' ) swap '[ @ _ mcall ] <reader> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
! Writer
|
|
|
|
SINGLETON: writer-monad
|
|
|
|
INSTANCE: writer-monad monad
|
|
|
|
|
|
|
|
TUPLE: writer value log ;
|
2013-03-24 04:38:25 -04:00
|
|
|
C: <writer> writer
|
2008-05-03 05:44:02 -04:00
|
|
|
|
|
|
|
M: writer monad-of drop writer-monad ;
|
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
M: writer-monad return drop { } <writer> ;
|
2008-05-03 05:44:02 -04:00
|
|
|
M: writer-monad fail "Fail" throw ;
|
|
|
|
|
|
|
|
: run-writer ( writer -- value log ) [ value>> ] [ log>> ] bi ;
|
|
|
|
|
2019-09-29 10:15:28 -04:00
|
|
|
M: writer >>= '[ [ _ run-writer ] dip '[ @ run-writer ] dip prepend <writer> ] ;
|
2008-05-03 05:44:02 -04:00
|
|
|
|
2013-03-24 04:38:25 -04:00
|
|
|
: pass ( writer -- writer' ) run-writer [ first2 ] dip swap call( x -- y ) <writer> ;
|
|
|
|
: listen ( writer -- writer' ) run-writer [ 2array ] keep <writer> ;
|
|
|
|
: tell ( seq -- writer ) f swap <writer> ;
|