{"action":"created","comment":{"url":"https://api.github.com/repos/clojure/clojure-site/pulls/comments/143191584","pull_request_review_id":67666989,"id":143191584,"diff_hunk":"@@ -0,0 +1,184 @@\n+= Higher Order Functions\n+Michael Zavarella\n+2017-09-15\n+:jbake-type: guides\n+:toc: macro\n+:icons: font\n+\n+ifdef::env-github,env-browser[:outfilesuffic: .adoc]\n+\n+toc:[]\n+\n+== First Class Functions\n+\n+In functional programming, functions are first class citizens.\n+This means functions can be treated as values.\n+They can be assigned as values, passed into functions, and returned from functions.\n+\n+It's common to see function definitions in Clojure using `defn` like `(defn foo ...)`.\n+However, this is just syntactic sugar for `(def foo (fn ...))`\n+`fn`, and implicitly `defn`, yield a function object as its value that can be passed around like any other Clojure object.\n+\n+== Higher Order Functions\n+\n+A higher order function is a function that either:\n+\n+1. Takes one or more functions as arguments\n+2. Returns a function as its result\n+\n+This will turn out to be a important concept in functional programming in any language.\n+\n+Higher order functions allow us to _compose_ functions.\n+This means we can write small functions and combine them to create larger functions.\n+Like putting a bunch of small lego bricks together to build a house.\n+\n+Let's move away from theory a bit and look at an example.\n+\n+=== Functions as Arguments\n+\n+Let's look at two functions\n+\n+[source, clojure]\n+----\n+(defn double-+\n+    [a b]\n+    (* 2 (+ a b)))\n+----\n+\n+[source, clojure]\n+----\n+(defn double-*\n+    [a b]\n+    (* 2 (* a b)))\n+----\n+\n+These functions share a common pattern.\n+They only differ in name and the function used in the computation of `a` and `b`.\n+In general, the pattern looks like this.\n+\n+[source, clojure]\n+----\n+(defn double-<f>\n+    [a b]\n+    (* 2 (f a b)))\n+----\n+\n+We can generalize our `double-` function by passing `f` in as an argument.\n+\n+[source, clojure]\n+----\n+(defn double-op\n+    [f a b]\n+    (* 2 (f a b)))\n+----\n+\n+We can use this to express the concept of doubling the result of an operation rather than having to write functions that perform specific doubled operations individually.\n+\n+== Anonymous Functions\n+\n+An anonymous function is a function without a name.\n+In Clojure these can be defined in two ways, `fn` and the literal `#(...)`.\n+Creating a function with `defn` immediately binds it to a name, `fn` just creates a function.\n+\n+Lets go back to the example of the bands.\n+We wrote a function called `rock-band?` to determine whether or not our band was a rock band.\n+This is a one-off operation, we're not going to use it anywhere else in our code.\n+We can save ourselves some keystrokes by using an anonymous function.\n+\n+[source, clojure]\n+----\n+(def rock-bands\n+    (filter\n+        (fn [band] (= :rock (:genre band)))\n+        bands))\n+----\n+\n+Even more concisely, using the function literal, we can define `rock-bands` like so.\n+\n+[source, clojure]\n+----\n+(def rock-bands (filter #(= :rock (:genre %)) bands))\n+----\n+\n+The function literal supports multiple arguments via `%1`, `%2`, and so on.\n+\n+[source, clojure]\n+----\n+#(println %1 %2 %3)\n+----\n+\n+If you're writing an anonymous function, the literal syntax is nice because it's so compact.\n+However, beyond a few arguments, the syntax can become difficult to read.\n+In that case, using `fn` may be more appropriate.\n+\n+=== Functions Returning Functions and Closures\n+\n+Our first function will be called `adder`.\n+It will take a number, `x`, as it's only argument and return a function.\n+The function returned by `adder` will also take a single number, `a`, as it's argument and return `x + a`.\n+\n+[source, clojure]\n+----\n+(defn adder [x]\n+  (fn [a] (+ x a)))\n+\n+(def add-five (adder 5))\n+\n+(add-five 100)\n+;; => 105\n+----\n+\n+The returned function form `adder` is a closure.\n+This means, it can access all of the variables that we're in scope when the function was created.\n+`add-five` has access to `x` even though it is outside of the `adder` function definition.\n+\n+=== Filter\n+\n+Filtering is a common operation in computer programming.\n+Take this set of animals\n+\n+[source, clojure]\n+----\n+(def pets [\n+    {:name \"Fluffykins\" :type :cat}\n+    {:name \"Sparky\" :type :dog}\n+    {:name \"Tibby\" :type :dog}\n+    {:name \"Al\" :type :fish}\n+    {:name \"Victor\" :type :bear}\n+])\n+----\n+\n+We want to filter out the dogs because we're writing enterprise grade software.\n+First, let's look at a normal for loop.\n+\n+[source, clojure]\n+----\n+(defn loop-dogs [pets]\n+    (loop [pets pets\n+           dogs []]\n+        (if (first pets)\n+            (recur (rest pets)\n+                   (if (= :dog (:type (first pets)))\n+                       (conj dogs (first pets))\n+                       dogs))\n+            dogs)))\n+----\n+\n+This code works fine, but it's bulky and confusing.\n+We can simplpify this using `filter`, a higher order function.","path":"content/guides/higher-order-functions.adoc","position":168,"original_position":168,"commit_id":"73b8971eea63f06b1996aaf836b3195830c811d1","original_commit_id":"73b8971eea63f06b1996aaf836b3195830c811d1","user":{"login":"puredanger","id":171129,"avatar_url":"https://avatars0.githubusercontent.com/u/171129?v=4","gravatar_id":"","url":"https://api.github.com/users/puredanger","html_url":"https://github.com/puredanger","followers_url":"https://api.github.com/users/puredanger/followers","following_url":"https://api.github.com/users/puredanger/following{/other_user}","gists_url":"https://api.github.com/users/puredanger/gists{/gist_id}","starred_url":"https://api.github.com/users/puredanger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puredanger/subscriptions","organizations_url":"https://api.github.com/users/puredanger/orgs","repos_url":"https://api.github.com/users/puredanger/repos","events_url":"https://api.github.com/users/puredanger/events{/privacy}","received_events_url":"https://api.github.com/users/puredanger/received_events","type":"User","site_admin":false},"body":"simplpify => simplify","created_at":"2017-10-06T13:37:57Z","updated_at":"2017-10-06T13:44:20Z","html_url":"https://github.com/clojure/clojure-site/pull/220#discussion_r143191584","pull_request_url":"https://api.github.com/repos/clojure/clojure-site/pulls/220","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/clojure/clojure-site/pulls/comments/143191584"},"html":{"href":"https://github.com/clojure/clojure-site/pull/220#discussion_r143191584"},"pull_request":{"href":"https://api.github.com/repos/clojure/clojure-site/pulls/220"}}},"pull_request":{"url":"https://api.github.com/repos/clojure/clojure-site/pulls/220","id":143278314,"html_url":"https://github.com/clojure/clojure-site/pull/220","diff_url":"https://github.com/clojure/clojure-site/pull/220.diff","patch_url":"https://github.com/clojure/clojure-site/pull/220.patch","issue_url":"https://api.github.com/repos/clojure/clojure-site/issues/220","number":220,"state":"open","locked":false,"title":"[WIP] Introduction to higher order functions guide","user":{"login":"admay","id":2299948,"avatar_url":"https://avatars3.githubusercontent.com/u/2299948?v=4","gravatar_id":"","url":"https://api.github.com/users/admay","html_url":"https://github.com/admay","followers_url":"https://api.github.com/users/admay/followers","following_url":"https://api.github.com/users/admay/following{/other_user}","gists_url":"https://api.github.com/users/admay/gists{/gist_id}","starred_url":"https://api.github.com/users/admay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/admay/subscriptions","organizations_url":"https://api.github.com/users/admay/orgs","repos_url":"https://api.github.com/users/admay/repos","events_url":"https://api.github.com/users/admay/events{/privacy}","received_events_url":"https://api.github.com/users/admay/received_events","type":"User","site_admin":false},"body":"Higher order functions aren't always the easiest thing to get a hold of for a beginner and there isn't anything on the official site that I've found yet, so I prioritized this one.\r\n\r\nRefers to [issue 131](https://github.com/clojure/clojure-site/issues/131) from a while back.\r\nTrying to get some of this in before the Conj.","created_at":"2017-09-27T01:21:21Z","updated_at":"2017-10-06T13:44:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"94e6eb2de9e424e727ba98b0ef6816e39da376df","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/clojure/clojure-site/pulls/220/commits","review_comments_url":"https://api.github.com/repos/clojure/clojure-site/pulls/220/comments","review_comment_url":"https://api.github.com/repos/clojure/clojure-site/pulls/comments{/number}","comments_url":"https://api.github.com/repos/clojure/clojure-site/issues/220/comments","statuses_url":"https://api.github.com/repos/clojure/clojure-site/statuses/73b8971eea63f06b1996aaf836b3195830c811d1","head":{"label":"admay:master","ref":"master","sha":"73b8971eea63f06b1996aaf836b3195830c811d1","user":{"login":"admay","id":2299948,"avatar_url":"https://avatars3.githubusercontent.com/u/2299948?v=4","gravatar_id":"","url":"https://api.github.com/users/admay","html_url":"https://github.com/admay","followers_url":"https://api.github.com/users/admay/followers","following_url":"https://api.github.com/users/admay/following{/other_user}","gists_url":"https://api.github.com/users/admay/gists{/gist_id}","starred_url":"https://api.github.com/users/admay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/admay/subscriptions","organizations_url":"https://api.github.com/users/admay/orgs","repos_url":"https://api.github.com/users/admay/repos","events_url":"https://api.github.com/users/admay/events{/privacy}","received_events_url":"https://api.github.com/users/admay/received_events","type":"User","site_admin":false},"repo":{"id":104955484,"name":"clojure-site","full_name":"admay/clojure-site","owner":{"login":"admay","id":2299948,"avatar_url":"https://avatars3.githubusercontent.com/u/2299948?v=4","gravatar_id":"","url":"https://api.github.com/users/admay","html_url":"https://github.com/admay","followers_url":"https://api.github.com/users/admay/followers","following_url":"https://api.github.com/users/admay/following{/other_user}","gists_url":"https://api.github.com/users/admay/gists{/gist_id}","starred_url":"https://api.github.com/users/admay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/admay/subscriptions","organizations_url":"https://api.github.com/users/admay/orgs","repos_url":"https://api.github.com/users/admay/repos","events_url":"https://api.github.com/users/admay/events{/privacy}","received_events_url":"https://api.github.com/users/admay/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/admay/clojure-site","description":"clojure.org site","fork":true,"url":"https://api.github.com/repos/admay/clojure-site","forks_url":"https://api.github.com/repos/admay/clojure-site/forks","keys_url":"https://api.github.com/repos/admay/clojure-site/keys{/key_id}","collaborators_url":"https://api.github.com/repos/admay/clojure-site/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/admay/clojure-site/teams","hooks_url":"https://api.github.com/repos/admay/clojure-site/hooks","issue_events_url":"https://api.github.com/repos/admay/clojure-site/issues/events{/number}","events_url":"https://api.github.com/repos/admay/clojure-site/events","assignees_url":"https://api.github.com/repos/admay/clojure-site/assignees{/user}","branches_url":"https://api.github.com/repos/admay/clojure-site/branches{/branch}","tags_url":"https://api.github.com/repos/admay/clojure-site/tags","blobs_url":"https://api.github.com/repos/admay/clojure-site/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/admay/clojure-site/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/admay/clojure-site/git/refs{/sha}","trees_url":"https://api.github.com/repos/admay/clojure-site/git/trees{/sha}","statuses_url":"https://api.github.com/repos/admay/clojure-site/statuses/{sha}","languages_url":"https://api.github.com/repos/admay/clojure-site/languages","stargazers_url":"https://api.github.com/repos/admay/clojure-site/stargazers","contributors_url":"https://api.github.com/repos/admay/clojure-site/contributors","subscribers_url":"https://api.github.com/repos/admay/clojure-site/subscribers","subscription_url":"https://api.github.com/repos/admay/clojure-site/subscription","commits_url":"https://api.github.com/repos/admay/clojure-site/commits{/sha}","git_commits_url":"https://api.github.com/repos/admay/clojure-site/git/commits{/sha}","comments_url":"https://api.github.com/repos/admay/clojure-site/comments{/number}","issue_comment_url":"https://api.github.com/repos/admay/clojure-site/issues/comments{/number}","contents_url":"https://api.github.com/repos/admay/clojure-site/contents/{+path}","compare_url":"https://api.github.com/repos/admay/clojure-site/compare/{base}...{head}","merges_url":"https://api.github.com/repos/admay/clojure-site/merges","archive_url":"https://api.github.com/repos/admay/clojure-site/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/admay/clojure-site/downloads","issues_url":"https://api.github.com/repos/admay/clojure-site/issues{/number}","pulls_url":"https://api.github.com/repos/admay/clojure-site/pulls{/number}","milestones_url":"https://api.github.com/repos/admay/clojure-site/milestones{/number}","notifications_url":"https://api.github.com/repos/admay/clojure-site/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/admay/clojure-site/labels{/name}","releases_url":"https://api.github.com/repos/admay/clojure-site/releases{/id}","deployments_url":"https://api.github.com/repos/admay/clojure-site/deployments","created_at":"2017-09-27T01:15:03Z","updated_at":"2017-09-27T01:15:06Z","pushed_at":"2017-09-29T00:45:19Z","git_url":"git://github.com/admay/clojure-site.git","ssh_url":"git@github.com:admay/clojure-site.git","clone_url":"https://github.com/admay/clojure-site.git","svn_url":"https://github.com/admay/clojure-site","homepage":null,"size":1548,"stargazers_count":0,"watchers_count":0,"language":"HTML","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"clojure:master","ref":"master","sha":"a0505fd1fb24375b04fbcf1dd50e716439b1edd6","user":{"login":"clojure","id":317875,"avatar_url":"https://avatars1.githubusercontent.com/u/317875?v=4","gravatar_id":"","url":"https://api.github.com/users/clojure","html_url":"https://github.com/clojure","followers_url":"https://api.github.com/users/clojure/followers","following_url":"https://api.github.com/users/clojure/following{/other_user}","gists_url":"https://api.github.com/users/clojure/gists{/gist_id}","starred_url":"https://api.github.com/users/clojure/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clojure/subscriptions","organizations_url":"https://api.github.com/users/clojure/orgs","repos_url":"https://api.github.com/users/clojure/repos","events_url":"https://api.github.com/users/clojure/events{/privacy}","received_events_url":"https://api.github.com/users/clojure/received_events","type":"Organization","site_admin":false},"repo":{"id":45919867,"name":"clojure-site","full_name":"clojure/clojure-site","owner":{"login":"clojure","id":317875,"avatar_url":"https://avatars1.githubusercontent.com/u/317875?v=4","gravatar_id":"","url":"https://api.github.com/users/clojure","html_url":"https://github.com/clojure","followers_url":"https://api.github.com/users/clojure/followers","following_url":"https://api.github.com/users/clojure/following{/other_user}","gists_url":"https://api.github.com/users/clojure/gists{/gist_id}","starred_url":"https://api.github.com/users/clojure/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clojure/subscriptions","organizations_url":"https://api.github.com/users/clojure/orgs","repos_url":"https://api.github.com/users/clojure/repos","events_url":"https://api.github.com/users/clojure/events{/privacy}","received_events_url":"https://api.github.com/users/clojure/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/clojure/clojure-site","description":"clojure.org site","fork":false,"url":"https://api.github.com/repos/clojure/clojure-site","forks_url":"https://api.github.com/repos/clojure/clojure-site/forks","keys_url":"https://api.github.com/repos/clojure/clojure-site/keys{/key_id}","collaborators_url":"https://api.github.com/repos/clojure/clojure-site/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/clojure/clojure-site/teams","hooks_url":"https://api.github.com/repos/clojure/clojure-site/hooks","issue_events_url":"https://api.github.com/repos/clojure/clojure-site/issues/events{/number}","events_url":"https://api.github.com/repos/clojure/clojure-site/events","assignees_url":"https://api.github.com/repos/clojure/clojure-site/assignees{/user}","branches_url":"https://api.github.com/repos/clojure/clojure-site/branches{/branch}","tags_url":"https://api.github.com/repos/clojure/clojure-site/tags","blobs_url":"https://api.github.com/repos/clojure/clojure-site/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/clojure/clojure-site/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/clojure/clojure-site/git/refs{/sha}","trees_url":"https://api.github.com/repos/clojure/clojure-site/git/trees{/sha}","statuses_url":"https://api.github.com/repos/clojure/clojure-site/statuses/{sha}","languages_url":"https://api.github.com/repos/clojure/clojure-site/languages","stargazers_url":"https://api.github.com/repos/clojure/clojure-site/stargazers","contributors_url":"https://api.github.com/repos/clojure/clojure-site/contributors","subscribers_url":"https://api.github.com/repos/clojure/clojure-site/subscribers","subscription_url":"https://api.github.com/repos/clojure/clojure-site/subscription","commits_url":"https://api.github.com/repos/clojure/clojure-site/commits{/sha}","git_commits_url":"https://api.github.com/repos/clojure/clojure-site/git/commits{/sha}","comments_url":"https://api.github.com/repos/clojure/clojure-site/comments{/number}","issue_comment_url":"https://api.github.com/repos/clojure/clojure-site/issues/comments{/number}","contents_url":"https://api.github.com/repos/clojure/clojure-site/contents/{+path}","compare_url":"https://api.github.com/repos/clojure/clojure-site/compare/{base}...{head}","merges_url":"https://api.github.com/repos/clojure/clojure-site/merges","archive_url":"https://api.github.com/repos/clojure/clojure-site/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/clojure/clojure-site/downloads","issues_url":"https://api.github.com/repos/clojure/clojure-site/issues{/number}","pulls_url":"https://api.github.com/repos/clojure/clojure-site/pulls{/number}","milestones_url":"https://api.github.com/repos/clojure/clojure-site/milestones{/number}","notifications_url":"https://api.github.com/repos/clojure/clojure-site/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/clojure/clojure-site/labels{/name}","releases_url":"https://api.github.com/repos/clojure/clojure-site/releases{/id}","deployments_url":"https://api.github.com/repos/clojure/clojure-site/deployments","created_at":"2015-11-10T15:12:16Z","updated_at":"2017-09-18T09:05:05Z","pushed_at":"2017-10-06T13:18:55Z","git_url":"git://github.com/clojure/clojure-site.git","ssh_url":"git@github.com:clojure/clojure-site.git","clone_url":"https://github.com/clojure/clojure-site.git","svn_url":"https://github.com/clojure/clojure-site","homepage":null,"size":1523,"stargazers_count":118,"watchers_count":118,"language":"HTML","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":90,"mirror_url":null,"open_issues_count":50,"forks":90,"open_issues":50,"watchers":118,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/clojure/clojure-site/pulls/220"},"html":{"href":"https://github.com/clojure/clojure-site/pull/220"},"issue":{"href":"https://api.github.com/repos/clojure/clojure-site/issues/220"},"comments":{"href":"https://api.github.com/repos/clojure/clojure-site/issues/220/comments"},"review_comments":{"href":"https://api.github.com/repos/clojure/clojure-site/pulls/220/comments"},"review_comment":{"href":"https://api.github.com/repos/clojure/clojure-site/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/clojure/clojure-site/pulls/220/commits"},"statuses":{"href":"https://api.github.com/repos/clojure/clojure-site/statuses/73b8971eea63f06b1996aaf836b3195830c811d1"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"puredanger"}}