Carp/examples/functor.carp
Scott Olsen 380945bf32
feat: add box type (#1358)
* feat: add box templates and box type

This commit adds an implementation of Boxes, memory manged heap
allocated values.

Boxes are implemented as C pointers, with no additional structure but
are treated as structs in Carp. To facilitate this, we need to add them
as a clause to our special type emissions (TypesToC) as they'd otherwise
be emitted like other struct types.

Co-authored-by: Veit Heller <veit@veitheller.de>

* fix: slight memory management fix for Box

Make sure we free the box!

* test: add tests for box (including memory checks)

* Revert "fix: Ignore clang nitpick"

This reverts commit 70ec6d46d4.

* fix: update example/functor.carp

Now that a builtin type named Box exists, the definitions in this file
cause a conflict. I've renamed the "Box" type in the functor example to
remove the conflict.

* feat: add Box.peek

Box.peek allows users to transform a reference to a box into a a
reference to the box's contained value. The returned reference will have
the same lifetime as the box. This function allows callers to manipulate
the value in a box without re-allocation, for example:

```clojure
(deftype Num [val Int])

(let-do [box (Box.init (Num.init 0))]
  (Num.set-val! (Box.peek &box) 1)
  @(Num.val (Box.peek &box)))
```

This commit also includes tests for Box.peek.

Co-authored-by: TimDeve <TimDeve@users.noreply.github.com>

Co-authored-by: Veit Heller <veit@veitheller.de>
Co-authored-by: Erik Svedäng <erik@coherence.io>
Co-authored-by: TimDeve <TimDeve@users.noreply.github.com>
2021-11-30 10:35:22 +01:00

41 lines
1.3 KiB
Plaintext

(use IO)
(use Int)
(use Array)
(Project.no-echo)
(definterface fmap (λ [(Ref (λ [a] b)) (f a)] (f b)))
(defmodule ArrayExtension
(defn fmap [f a] (Array.endo-map f a))
(implements fmap ArrayExtension.fmap)
)
(deftype (MyBox a) [x a])
(defmodule MyBox
(defn fmap [f box] (let [new-x (~f @(MyBox.x &box))]
(MyBox.set-x box new-x)))
(implements fmap MyBox.fmap))
(use MyBox)
(use ArrayExtension)
;; TODO: This function currently concretizes to the type of the first (f *) it
;; receives. Is there a way for us to ensure it remains generic?
;; N.B. the only reason it worked previously was because it was ill-typed as
;; (a -> a) which erroneously served as a universal type.
;(sig higherOrder (Fn [(f a)] (f b)))
;(defn higherOrder [x] (fmap &Int.inc x))
(defn main []
(do
(println &(str @(MyBox.x &(fmap &Int.inc (MyBox.init 100)))))
(println &(str @(MyBox.x &(MyBox.fmap &inc (MyBox.init 100)))))
(println &(str &(ArrayExtension.fmap &inc [10 20 30 40 50])))
(println &(str &(fmap &Int.inc [10 20 30 40 50])))
(println &(Array.str &(fmap &Int.inc [10 20 30 40 50])))
(println &(Array.str &(ArrayExtension.fmap &Int.inc [10 20 30 40 50])))
;(println &(str &(higherOrder (Box.init 999))))
;(println &(str &(higherOrder [9 99 999 9999])))
))