@robashton
Lazy + Purity = Great Success
(Mostly) Strict + Impurity = Great Imperative Success Batman
Laziness + Side Effects = ???
(defn pony-list []
(with-open [rdr (reader "/tmp/ponies.txt")]
(map to-pony (line-seq rdr))))
(pony-list) ;; CRASH
(defn pony-list []
(with-open [rdr (reader "/tmp/ponies.txt")]
(doall (map to-pony (line-seq rdr)))))
(defn read-ponies
([reader] (read-ponies reader (read-some-results reader)))
([page src]
(cond
;; No more left, close reader, return empty list
;; Need more ponies, read ponies and recurse
;; cons some ponies and lazy-seq recurse
(Reducers work too)
(etc)
(with-ponies pony-list [f]
(with-open [rdr (reader "/tmp/ponies.txt")]
(f (map to-pony (line-seq rdr)))))
(defprotocol
Java.io.Closeable
(read-ponies [])
(close))
Or
interface NativeIterator : Iterator
{
// Come from Iterator
boolean hasNext();
E next();
void remove();
// Because something dangerous is down there
close();
}
(defn get-ponies []
(with-open [iter (create-iterator)]
(iterator-seq iter)))
(get-ponies) ;; CRASH
(defn create-iter [])
(defn next-pony [iter])
(defn close-iter [iter])
(Or a protocol)
(and concurrency)
Lucene indexes
LevelDB handles
etc
More than one concurrent user (hopefully)
HTTP PUT /indexes/1
HTTP PUT /indexes/1
HTTP DELETE /indexes/1
HTTP DELETE /indexes/2
lock(database) {
// Do stuff to database
}
(agents etc)
(defn create-controlled-index [i]
(agent (create-index i))
(add-item-to-index [index item]
(send index add-item-inner item))
(nope nope nope nope nope)
(defn setup-indexes [db]
(let [command-channel (chan)
;; Set up a loop with that channel
(do-indexing-loop command-channel)
;; Pass back that channel to consumers for input
(assoc db :index-commands command-channel)))
;; Provide API over that channel
(defn add-index [cc index]
(>! cc {:cmd :add-index :data index})))
(defn go-index-head [_ {:keys [command-channel] :as engine}]
(debug "being asked to start")
(go
(loop [state (initial-state engine)]
(if-let [{:keys [cmd data]} (<! command-channel)]
(do
(debug "handling index loop command" cmd)
(recur (case cmd
:schedule-indexing (main-indexing-process state)
:notify-finished-indexing (main-indexing-process-ended state)
:new-index (add-chaser state data)
:chaser-finished (finish-chaser state data)
:storage-request (storage-request state data))))
(do
(debug "being asked to shut down")
(wait-for-main-indexing state)
(wait-for-chasers state)
(close-open-indexes state))))))
handle_info({ add_index, Index }, State) ->
add_index(Index, State);
handle_info({ remove_index, Index }, State) ->
remove_index(Index, State);
handle_info({ flush_index, Index }, State) ->
flush_index(Index, State);
(except without supervisors, processes, useful error messages, boundaries, messaging)
Use Erlang