aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/control/concurrency/behavioral.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/library/lux/control/concurrency/behavioral.lux')
-rw-r--r--stdlib/source/library/lux/control/concurrency/behavioral.lux50
1 files changed, 50 insertions, 0 deletions
diff --git a/stdlib/source/library/lux/control/concurrency/behavioral.lux b/stdlib/source/library/lux/control/concurrency/behavioral.lux
new file mode 100644
index 000000000..1865558aa
--- /dev/null
+++ b/stdlib/source/library/lux/control/concurrency/behavioral.lux
@@ -0,0 +1,50 @@
+(.require
+ [library
+ [lux (.except)]]
+ [//
+ ["[0]" async (.only Async) (.use "[1]#[0]" monad)]
+ ["[0]" frp (.only Channel)]])
+
+(def <Event>
+ (template (_ Constructor data)
+ [[(Constructor data) data]]))
+
+(type .public (Constructor data)
+ (-> data (<Event> Constructor data)))
+
+(type .public Event
+ (Ex (_ data)
+ (<Event> Constructor data)))
+
+(def .public (event constructor)
+ (All (_ data)
+ (-> (-> data data)
+ (Constructor data)))
+ (exec
+ [] ... This was added to avoid having auto-currying to fuse the "event" and "self" functions.
+ ... Otherwise, the "same?" comparison done later would fail.
+ (function (self data)
+ [self (constructor data)])))
+
+(def .public (event? expected it)
+ (All (_ data)
+ (-> (Constructor data) Event
+ (Maybe data)))
+ (let [[actual data] it]
+ (if (same? expected actual)
+ {.#Some (as_expected data)}
+ {.#None})))
+
+(def .public (scenario events expected initial behavior)
+ (All (_ state data)
+ (-> (Channel Event) (Constructor data) state (-> data state (Async state))
+ (Async state)))
+ (frp.mix (function (_ event state)
+ (when (event? expected event)
+ {.#Some data}
+ (behavior data state)
+
+ {.#None}
+ (async#in state)))
+ initial
+ events))