# HG changeset patch # User IBBoard # Date 1559850976 -3600 # Node ID 0f57e5c2ae82a503d68658b673e4b09b74fc3508 # Parent a83309cdf5d35e4d5c06d11a150cd1f9727a61e5 Add notes on sequences in Clojure Next up: infinite sequences! diff -r a83309cdf5d3 -r 0f57e5c2ae82 6-Clojure/README.txt --- a/6-Clojure/README.txt Thu Jun 06 20:26:42 2019 +0100 +++ b/6-Clojure/README.txt Thu Jun 06 20:56:16 2019 +0100 @@ -37,10 +37,10 @@ Note: 0 and "" are true but nil is false, so only false and the null value are falsey. -Clojure has four main data structures - lists (for code), vectors (for data), sets and maps. +Clojure has four main data structures - lists (for code), vectors (for data), sets and maps. These are types of sequence. Other things may also be sequences (strings, file system structures, etc). +Sequences can then be operated on with "first", "last", "rest" and "cons" (construct from head and tail) functions. You can't build a list Python style with "(1 2 3)". You need either "(list 1 2 3)" or the odd syntax "'(1 2 3)". -Lists can then be operated on with "first", "last", "rest" and "cons" (construct from head and tail) functions. There are also functions like "nth" (nth <0-based index>) Vectors use sequare brackets. They're like a list, but you can implicitly index them (i.e. you don't need "nth") by doing ([vector] pos) because they're treated as functions. @@ -79,7 +79,29 @@ As well as the map function, there's "apply" and "filter". -Also, some helper functions exist, like "odd?". +Also, some helper functions exist, like "odd?". Terminating in a question mark seems to be the Clojure approach to predicates. Sometimes you end up with multiple question marks: + +(every? number? [1 2 3 :four]) +;false + +not-every? and not-any? both have question marks as well. But not everything is question marked: + +(some nil? [1 2 nil]) +; true + +This seems oddly inconsistent. The footnote explains that it's because "some returns the first value that is not nil or false", so "nil?" return false for 1 and 2 and then return true for nil and so some returns it. +It's not a predicate because "(some nil? [1 2]) returns nil, not false. Functional languages do lazy tail recursion. Unless they're Clojure, because the JVM doesn't support it. Clojure does it with a "loop" and a "recur" function. "loop" takes x and y with initial values and a function to call. See loop_recur.clj. +For loops take the form (for [val collection<, val2 collection2<, …>>] (body)), which is a bit like "for X in Collection", but doesn't look like it at first. +Multiple val/collection pairs give nested for loops (so every val with every val2). + +But then for loops can take a ":when" test keyword (or :let or :while). Which is odd, because :xxx has only ever been a user atom, but this one already has meaning. And they can be mixed anywhere in the parameters and Clojure knows what to do. + +Reduce is more familiar: (reduce func list) + +(reduce + [1 2 3 4]) ; sums +(reduce * [1 2 3 4 5]) ; factorial + +As well as sorting a list with (sort list) you can use a custom funcion with (sort-by function list) where "function" takes a single parameter and generates a key. \ No newline at end of file