aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Julian2019-02-04 20:37:54 -0400
committerEduardo Julian2019-02-04 20:37:54 -0400
commit7e4479b927f400e617602a8686683e14a7f2f74a (patch)
treed5f5f117cace26e19f6a54b78d78b524df250974
parent02bd27592bb36efb97120f2c852374130209017d (diff)
Re-implemented the IO type as an abstract type in order to avoid potential issues with sub-typing during type-checking.
-rw-r--r--luxc/src/lux/type.clj4
-rw-r--r--stdlib/source/lux/host.jvm.lux15
-rw-r--r--stdlib/source/lux/io.lux104
3 files changed, 69 insertions, 54 deletions
diff --git a/luxc/src/lux/type.clj b/luxc/src/lux/type.clj
index 9a1e12e18..ec8849601 100644
--- a/luxc/src/lux/type.clj
+++ b/luxc/src/lux/type.clj
@@ -66,9 +66,9 @@
(&/$Parameter 1))))
(def IO
- (&/$Named (&/T ["lux/codata" "IO"])
+ (&/$Named (&/T ["lux/io" "IO"])
(&/$UnivQ empty-env
- (&/$Function Nothing (&/$Parameter 1)))))
+ (&/$Primitive "lux/type/abstract.Abstraction lux/io.IO" (&/|list (&/$Parameter 1))))))
(def List
(&/$Named (&/T ["lux" "List"])
diff --git a/stdlib/source/lux/host.jvm.lux b/stdlib/source/lux/host.jvm.lux
index 7c27c9f63..c788380c8 100644
--- a/stdlib/source/lux/host.jvm.lux
+++ b/stdlib/source/lux/host.jvm.lux
@@ -1430,13 +1430,16 @@
("jvm object null")}
(~ expr)))))))
-(syntax: #export (try expr)
- {#.doc (doc "Covers the expression in a try-catch block."
- "If it succeeds, you get (#.Right result)."
- "If it fails, you get (#.Left error+stack-traces-as-text)."
- (try (risky-computation input)))}
+(syntax: #export (try expression)
+ {#.doc (doc (case (try (risky-computation input))
+ (#.Right success)
+ (do-something success)
+
+ (#.Left error)
+ (recover-from-failure error)))}
(with-gensyms [g!_]
- (wrap (list (`' ("lux try" (.function ((~ g!_) (~ g!_)) (~ expr))))))))
+ (wrap (list (` ("lux try" ((~! io.label) (.function ((~ g!_) (~ g!_))
+ (~ expression)))))))))
(syntax: #export (check {#let [imports (class-imports *compiler*)]}
{class (generic-type^ imports (list))}
diff --git a/stdlib/source/lux/io.lux b/stdlib/source/lux/io.lux
index 7fdccda95..4da9fe897 100644
--- a/stdlib/source/lux/io.lux
+++ b/stdlib/source/lux/io.lux
@@ -1,53 +1,65 @@
-## TODO: Make IO an abstract type.
(.module: {#.doc "A method for abstracting I/O and effectful computations to make it safe while writing pure functional code."}
[lux #*
[control
[functor (#+ Functor)]
[apply (#+ Apply)]
- [monad (#+ do Monad)]]])
+ [monad (#+ Monad do)]]
+ [type
+ abstract]
+ ["." macro (#+ with-gensyms)
+ ["s" syntax (#+ syntax:)]
+ ["." template]]])
-(type: #export (IO a)
+(abstract: #export (IO a)
{#.doc "A type that represents synchronous, effectful computations that may interact with the outside world."}
- (-> Nothing a))
-
-(macro: #export (io tokens state)
- {#.doc (doc "Delays the evaluation of an expression, by wrapping it in an IO 'thunk'."
- "Great for wrapping effectful computations (which will not be performed until the IO is 'run')."
- (io (exec
- (log! msg)
- "Some value...")))}
- (case tokens
- (^ (list value))
- (let [blank (: Code [["" 0 0] (#.Identifier ["" ""])])]
- (#.Right [state (list (` ([(~ blank) (~ blank)] (~ value))))]))
-
- _
- (#.Left "Wrong syntax for io")))
-
-(structure: #export functor (Functor IO)
- (def: (map f ma)
- (io (f (ma (:coerce Nothing []))))))
-
-(structure: #export apply (Apply IO)
- (def: &functor ..functor)
-
- (def: (apply ff fa)
- (io ((ff (:coerce Nothing [])) (fa (:coerce Nothing []))))))
-
-(structure: #export monad (Monad IO)
- (def: &functor ..functor)
-
- (def: (wrap x)
- (io x))
-
- (def: (join mma)
- (io ((mma (:coerce Nothing [])) (:coerce Nothing [])))))
-
-(def: #export (run action)
- {#.doc "A way to execute IO computations and perform their side-effects."}
- (All [a] (-> (IO a) a))
- (action (:coerce Nothing [])))
-
-(def: #export (exit code)
- (-> Int (IO Nothing))
- (io ("lux io exit" code)))
+ (-> Nothing a)
+
+ (def: #export (label thunk)
+ (All [a] (-> (-> Nothing a) (IO a)))
+ (:abstraction thunk))
+
+ (template: (!io computation)
+ (:abstraction (template.with-locals [g!func g!arg]
+ (function (g!func g!arg)
+ computation))))
+
+ (template: (!execute io)
+ ## creatio ex nihilo
+ ((:representation io) (:coerce .Nothing [])))
+
+ (syntax: #export (io computation)
+ {#.doc (doc "Delays the evaluation of an expression, by wrapping it in an IO 'thunk'."
+ "Great for wrapping effectful computations (which will not be performed until the IO is 'run')."
+ (io (exec
+ (log! msg)
+ "Some value...")))}
+ (with-gensyms [g!func g!arg]
+ (wrap (list (` ((~! ..label) (function ((~ g!func) (~ g!arg))
+ (~ computation))))))))
+
+ (def: #export (exit code)
+ (-> Int (IO Nothing))
+ (!io ("lux io exit" code)))
+
+ (def: #export run
+ {#.doc "A way to execute IO computations and perform their side-effects."}
+ (All [a] (-> (IO a) a))
+ (|>> !execute))
+
+ (structure: #export functor (Functor IO)
+ (def: (map f)
+ (|>> !execute f !io)))
+
+ (structure: #export apply (Apply IO)
+ (def: &functor ..functor)
+
+ (def: (apply ff fa)
+ (!io ((!execute ff) (!execute fa)))))
+
+ (structure: #export monad (Monad IO)
+ (def: &functor ..functor)
+
+ (def: wrap (|>> !io))
+
+ (def: join (|>> !execute !execute !io)))
+ )