Read and Eval
Read code from standard input:
(read)
Read, evaluate and execute code from a string:
(def func-text "(defn plus [a b] (+ a b))")
(def func-data (read-string func-text))
(def func-eval (eval func-data))
(func-eval 4 5) ; 9
Write a REPL:
(defn repl []
(loop []
(println (eval (read)))
(recur)))
Attach metadata to data and get it back:
(def songs-data ["Pale Fire" "Monument"])
(def songs-meta (with-meta songs-data {:note "I especially like 'Pale Fire'"}))
(meta songs-meta) ; {:note "I especially like 'Pale Fire'"}
Metadata is not dealt with separate from regular data:
(def points-a [3 5 8])
(def points-b [3 5 8])
(= points-a points-b) ; true
(def meta-points-a (with-meta points-a {:measured "yesterday"}))
(def meta-points-b (with-meta points-b {:measured "today"}))
(= meta-points-a meta-points-b) ; true
(= (meta meta-points-a) (meta meta-points-b)) ; false
Exercises
Read Song Data
Save the following song data to disk, e.g. under /tmp/songs.clj
:
{:name "Aces High" :band "Iron Maiden" :album "Powerslave" :year 1984}
{:name "Damnation" :band "Fates Warning" :album "Night on Bröcken" :year 1984}
{:name "The Apparition" :band "Fates Warning" :album "Spectre Within" :year 1985}
{:name "Wasted Years" :band "Iron Maiden" :album "Somewhere in Time" :year 1986}
{:name "Giant's Lore" :band "Fates Warning" :album "Awaken the Guardian" :year 1986}
{:name "The Ivory Gate of Dreams" :band "Fates Warning" :album "No Exit" :year 1988}
{:name "Infinite Dreams" :band "Iron Maiden" :album "Seventh Son of a Seventh Son" :year 1988}
{:name "Through Different Eyes" :band "Fates Warning" :album "Perfect Symmetry" :year 1989}
{:name "Fates Warning" :band "Iron Maiden" :album "No Prayer for the Dying" :year 1990}
{:name "Life in Still Water" :band "Fates Warning" :album "Parallels" :year 1991}
{:name "Judas Be My Guide" :band "Iron Maiden" :album "Fear of the Dark" :year 1992}
{:name "Pale Fire" :band "Fates Warning" :album "Inside Out" :year 1994}
{:name "Monument" :band "Fates Warning" :album "Inside Out" :year 1994}
{:name "Lord of the Flies" :band "Iron Maiden" :album "The X Factor" :year 1995}
Write a function songs-from-file
that expects a path as parameter
and returns a vector of songs.
Hint: Use slurp
to read the data. Use clojure.string/split-lines
to separate the string into lines. Use read-string
to turn the lines
into data.
Test: (count (songs-from-file "/tmp/songs.clj"))
shall return 14
.
Read Function Data
Save the following code to disk, e.g. under /tmp/funcs.clj
:
(with-meta (fn [s] (< (:year s) 1990)) {:kind :filter})
(with-meta (fn [s] (clojure.string/includes? (:name s) "Dream")) {:kind :filter})
(with-meta (fn [s] (= (:band s) "Fates Warning")) {:kind :filter})
(with-meta (fn [s] (str (:name s) " (" (:album s) ", " (:year s) ")")) {:kind :mapper})
Write a function funcs-from-file
that expects a path as parameter
and returns a vector of functions.
Hint: Use comp
to combine read-string
and eval
into a single
operation.
Test: (count (funcs-form-file "/tmp/funcs.clj"))
shall return 4.
Song Processing Pipeline
Write a function run-pipeline
that expects a sequence of songs (as
from the first exercise) and a sequence of functions (as from the
second exercise). The function shall process the given songs using the
given functions to be executed as a pipeline, i.e. one by one
according to its metadata: If a function is of the kind :filter
, it
shall be executed as a predicate to filter
; if it is of the kind
:mapper
, it sh all be executed as a transformer to map
.
Hint: Use the meta
function to access the metadata of the pipeline
function.
Test: (run-pipeline (songs-from-file "/tmp/songs.clj") (funcs-from-file "/tmp/funcs.clj"))
shall return:
("The Ivory Gate of Dreams (No Exit, 1989)")