~jojo/Carth

36b6008c65cdf9373cbdd0a3b26fde6e68e79dd5 — JoJo 1 year, 1 month ago d43904b
std: rename mod Memo back to Lazy & make Lazy thread safe

The evaluation and store of the computation of a Lazy is now
considered a critical section and locked behind a Mutex, which means
we will be able to share the same lazy value between threads, and they
will all be able to read it, and it will only be evaluated once.
8 files changed, 44 insertions(+), 24 deletions(-)

M TODO.org
M src/Check.hs
M std/io.carth
A std/lazy.carth
M std/macros.carth
M std/mem.carth
D std/memo.carth
M std/std.carth
M TODO.org => TODO.org +1 -0
@@ 732,3 732,4 @@ Features and other stuff to do/implement in/around Carth.
      MyOtherErr(OtherErr)
  }
  #+END_SRC
* INACTIVE Hygienic macros

M src/Check.hs => src/Check.hs +7 -1
@@ 113,7 113,13 @@ builtinDataTypes' =
      )
    , ("Unit", [], [unit'])
    , ("RealWorld", [], [("UnsafeRealWorld", [])])
    , ("Bool", [], [("False", []), ("True", [])])
    , ( "Bool"
      , []
      , [("False", []), ("True", [])]
      )
    -- TODO: Since Carth is not otherwise a lazy language, our IO computations should
    --       maybe not be either. Diverge from Haskell and just make IO a sort of
    --       marker without the realworld function shebang.
    , ( "IO"
      , [TVImplicit 0]
      , [ ( "IO"

M std/io.carth => std/io.carth +3 -0
@@ 43,3 43,6 @@

(extern unsafe-read-file (Fun Str (Maybe Str)))
(define (read-file f) (IO (fun (real-world) [(unsafe-read-file f) real-world])))

(define (io/write-ref x ptr)
  (io/wrap (store x ptr)))

A std/lazy.carth => std/lazy.carth +20 -0
@@ 0,0 1,20 @@
(import macros)
(import sync)
(import io)

(data (Lazy a)
  (Lazy [Mutex (Box (Either (Fun Unit a) a))]))

(define: (strict (Lazy [mx ptr]))
    (forall (a) (Fun (Lazy a) a))
  (unsafe-perform-io
   (io/thenr
    (mutex/lock mx)
    (match (deref ptr)
      (case (Left f)
            (let ((x (f Unit)))
              (apps io/thenr
                    (io/write-ref (Right x) ptr)
                    (mutex/release mx)
                    (io/pure x))))
      (case (Right x) (io/thenr (mutex/release mx) (io/pure x)))))))

M std/macros.carth => std/macros.carth +7 -0
@@ 10,3 10,10 @@
  (case (xs ...) (appsr list/cons xs ... Nil)))

(defmacro +s (case (xs ...) (apps + xs ...)))

(defmacro io/wrap
  (case (computation) (IO (fun (real-world) [computation real-world]))))

(defmacro lazy
  (case (computation) (Lazy [(unsafe-perform-io mutex/new)
                             (box (Left (fun (Unit) computation)))])))

M std/mem.carth => std/mem.carth +5 -1
@@ 1,6 1,6 @@
(define: (box x)
    (forall (a) (Fun a (Box a)))
  (store x (transmute (id@"GC_malloc" (sizeof a)))))
  (store x (cast-ptr (id@"GC_malloc" (sizeof a)))))

(define: cast-ptr
    (forall (a b) (Fun (Box a) (Box b)))


@@ 8,3 8,7 @@

(define: (ptr/+ ptr x) (forall (a) (Fun (Box a) Nat (Box a)))
  (transmute (+ (transmute ptr) (* x (cast (sizeof a))))))

(define: (mem/unsafe-null Unit)
    (forall (a) (Fun Unit (Box a)))
  (transmute 0))

D std/memo.carth => std/memo.carth +0 -21
@@ 1,21 0,0 @@
;; Memoization
;;
;; A bit like lazy evaluation, but only the result caching part -- no thunk-wise
;; evaluation.

(import std)

(data (Memo a)
  (Memo (Box (Either (Fun Unit a) a))))

(define: (memoize f)
    (forall (a) (Fun (Fun Unit a) (Memo a)))
  (Memo (box (Left f))))

(define: (remember (Memo ptr))
    (forall (a) (Fun (Memo a) a))
  (match (deref ptr)
    (case (Left f) (let ((x (f Unit)))
                     (seq (store (Right x) ptr)
                          x)))
    (case (Right x) x)))

M std/std.carth => std/std.carth +1 -1
@@ 4,7 4,7 @@
(import maybe)
(import either)
(import math)
(import memo)
(import lazy)
(import mem)
(import array)
(import string)