Skip to content

Commit

Permalink
Initial implementation including Reader and State effects.
Browse files Browse the repository at this point in the history
  • Loading branch information
Pauli Jaakkola committed Aug 27, 2018
1 parent 58d4c5d commit e9a7eda
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ pom.xml.asc
/.nrepl-port
.hgignore
.hg/
.idea/
*.iml
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
# fell
# Fell

A Clojure library designed to ... well, that part is up to you.
Freer monads for Clojure and [funcool/cats](http://funcool.github.io/cats/latest/) based on
[Freer Monads, More Extensible Effects](http://okmij.org/ftp/Haskell/extensible/more.pdf).

## Usage

FIXME
Don't.

```clojure
(ns fell.example
(:require [fell.core :refer [send state-runner run-reader run]]
[cats.core :refer [mlet return]]))

(def run-counter (state-runner :counter-state))

(def run-status (state-runner :status-state))

(def stateful-computation
(mlet [initial-status (send [:status-state :get])
counter (send [:counter-state :get])
increment (send [:reader/get])
_ (send [:counter-state :set (+ counter increment)])
counter* (send [:counter-state :get])
_ (send [:status-state :set (str "Energy: " counter)])]
(return initial-status)))

(-> stateful-computation
(run-counter 8)
(run-reader 17)
(run-status "Asleep")
run) ;=> [["Asleep" 25] "Energy: 8"]
```

## License

Expand Down
5 changes: 3 additions & 2 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(defproject fell "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:description "Freer monads for Clojure"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.8.0"]])
:dependencies [[org.clojure/clojure "1.9.0"]
[funcool/cats "2.2.0"]])
6 changes: 0 additions & 6 deletions src/fell/core.clj

This file was deleted.

73 changes: 73 additions & 0 deletions src/fell/core.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
(ns fell.core
(:require [cats.protocols :refer [Contextual Extract -extract Context Monad]]))

(defn- singleton-queue [v]
#?(:clj (conj clojure.lang.PersistentQueue/EMPTY v)
:cljs #queue [v]))

(declare context)

(deftype Pure [v]
Contextual
(-get-context [_] context)

Extract
(-extract [_] v))

(deftype Impure [request cont]
Contextual
(-get-context [_] context))

(def context
(reify
Context

Monad
(-mreturn [_ v] (Pure. v))
(-mbind [_ mv f]
(condp instance? mv
Pure (f (-extract mv))
Impure (Impure. (.-request mv) (conj (.-cont mv) f))))))

(defn- apply-queue [queue v]
(let [mv ((peek queue) v)
queue* (pop queue)]
(if (seq queue*)
(condp instance? mv
Pure (recur queue* (-extract mv))
Impure (Impure. (.-request mv) (into (.-cont mv) queue*)))
mv)))

(defn append-handler [queue handle]
(comp handle (partial apply-queue queue)))

(defn send [request]
(Impure. request (singleton-queue ->Pure)))

(defn handle-relay [can-handle? ret handle mv]
(condp instance? mv
Pure (ret (-extract mv))
Impure (let [request (.-request mv)
cont (append-handler (.-cont mv)
(partial handle-relay can-handle? ret handle))]
(if (can-handle? (.-request mv))
(handle request cont)
(Impure. request (singleton-queue cont))))))

(defn run-reader [mv ctx]
(handle-relay #(= (first %) :reader/get) ->Pure (fn [[_] cont] (cont ctx)) mv))

(defn state-runner [label]
(fn run-state [mv domain-state]
(condp instance? mv
Pure (Pure. [(-extract mv) domain-state])
Impure (let [[tag subtag state* :as request] (.-request mv)
make-cont (fn [domain-state]
(append-handler (.-cont mv) #(run-state % domain-state)))]
(if (= tag label)
(case subtag
:get ((make-cont domain-state) domain-state)
:set ((make-cont state*) nil))
(Impure. request (singleton-queue (make-cont domain-state))))))))

(def run -extract)

0 comments on commit e9a7eda

Please sign in to comment.