emacs.d/clones/lisp/clojure-doc.org/articles/language/functions/index.html

398 lines
27 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8"/>
<title>Clojure Guides: Functions in Clojure</title>
<meta name="description" content="This guide covers:">
<meta property="og:description" content="This guide covers:">
<meta property="og:url" content="https://clojure-doc.github.io/articles/language/functions/" />
<meta property="og:title" content="Functions in Clojure" />
<meta property="og:type" content="article" />
<link rel="canonical" href="https://clojure-doc.github.io/articles/language/functions/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Alegreya:400italic,700italic,400,700" rel="stylesheet"
type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/styles/default.min.css">
<link href="../../../css/screen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="../../../index.html">Clojure Guides</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li ><a href="../../../index.html">Home</a></li>
<li><a href="https://github.com/clojure-doc/clojure-doc.github.io">Contribute</a></li>
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</nav>
<div class="container">
<div class="row">
<div class="col-lg-9">
<div id="content">
<div id="custom-page">
<div id="page-header">
<h2>Functions in Clojure</h2>
</div>
<p>This guide covers:</p><ul><li>How to define functions</li><li>How to invoke functions</li><li>Multi-arity functions</li><li>Variadic functions</li><li>Higher order functions</li><li>Other topics related to functions</li></ul><p>This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>
(including images &amp; stylesheets). The source is available <a href="https://github.com/clojure-doc/clojure-doc.github.io">on Github</a>.</p><h2 id="what-version-of-clojure-does-this-guide-cover">What Version of Clojure Does This Guide Cover?</h2><p>This guide covers Clojure 1.5.</p><h2 id="overview">Overview</h2><p>Clojure is a functional programming language. Naturally, functions are very important part of Clojure.</p><h2 id="how-to-define-functions">How To Define Functions</h2><p>Functions are typically defined using the <a href="http://clojuredocs.org/clojure_core/clojure.core/defn">defn</a> macro:</p><pre><code class="clojure">(defn round
[d precision]
(let [factor (Math/pow 10 precision)]
(/ (Math/floor (* d factor)) factor)))
</code></pre><p>Functions can have doc strings (documentation strings) and it is a good idea to document functions that
are part of the public API:</p><pre><code class="clojure">(defn round
"Round down a double to the given precision (number of significant digits)"
[d precision]
(let [factor (Math/pow 10 precision)]
(/ (Math/floor (* d factor)) factor)))
</code></pre><p>In Clojure, function arguments may have optional type hints:</p><pre><code class="clojure">(defn round
[^double d ^long precision]
(let [factor (Math/pow 10 precision)]
(/ (Math/floor (* d factor)) factor)))
</code></pre><p>Type hints sometimes allow the compiler to avoid reflective method calls and/or produce significantly more efficient bytecode.
However, as a rule of thumb, it is usually not necessary to use type hints. Start writing your code without them. The compiler
is also free to ignore provided hints.</p><p>Functions can also define <em>preconditions</em> and <em>postconditions</em> that put restrictions on argument values and
the value function returns:</p><pre><code class="clojure">(defn round
"Round down a double to the given precision (number of significant digits)"
[^double d ^long precision]
{:pre [(not-nil? d) (not-nil? precision)]}
(let [factor (Math/pow 10 precision)]
(/ (Math/floor (* d factor)) factor)))
</code></pre><p>In the example above, we use preconditions to check that both arguments are not nil. The <code>not-nil?</code> macro (or function) is not
demonstrated in this example and assumed to be implemented elsewhere.</p><h2 id="anonymous-functions">Anonymous Functions</h2><p>Anonymous functions are defined using the <code>fn</code> special form:</p><pre><code class="clojure">(fn [x]
(* 2 x))
</code></pre><p>Anonymous functions can be assigned to locals, passed between functions (higher order functions are covered later in this document)
and returned from functions:</p><pre><code class="klipse-clojure nohighlight">(let [f (fn [x]
(* 2 x))]
(map f (range 0 10)))
</code></pre><p>There is also a reader macro for anonymous functions:</p><pre><code class="klipse-clojure nohighlight">(let [f #(* 2 %)]
(map f (range 0 10)))
</code></pre><p>The <code>%</code> in the example above means "the first argument". To refer to more than one argument, use <code>%1</code>, <code>%2</code> and so on:</p><pre><code class="klipse-clojure nohighlight">;; an anonymous function that takes 3 arguments and adds them together
(let [f #(+ %1 %2 %3)]
(f 1 2 3))
</code></pre><p>Please <strong>use this reader macro sparingly</strong>; excessive use may lead to unreadable code.</p><h2 id="how-to-invoke-functions">How To Invoke Functions</h2><p>Functions are invoked by placing a function to the leading position (<em>the calling position</em>) of a list:</p><pre style="visibility:hidden; height:0;"><code class="klipse-clojure nohighlight">
(import '(goog.string format))
</code></pre><pre><code class="klipse-clojure nohighlight">(format "Hello, %s" "world")
</code></pre><p>This works also if you have a function stored in a local, a var or passed as an argument:</p><pre><code class="klipse-clojure nohighlight">(let [f format]
(f "Hello, %s" "world"))
</code></pre><p>Alternatively, you can call a function using <a href="http://clojuredocs.org/clojure_core/clojure.core/apply">clojure.core/apply</a></p><pre><code class="klipse-clojure nohighlight">(apply format "Hello, %s" ["world"])
</code></pre><pre><code class="klipse-clojure nohighlight">(apply format "Hello, %s %s" ["Clojure" "world"])
</code></pre><p><code>clojure.core/apply</code> is usually only necessary when calling variadic functions or having the list of arguments passed in
as a collection.</p><h2 id="multi-arity-functions">Multi-arity Functions</h2><p>Functions in Clojure can have multiple <em>arities</em>, or sets of arguments:</p><pre><code class="clojure">(defn tax-amount
([amount]
(tax-amount amount 35))
([amount rate]
(Math/round (double (* amount (/ rate 100))))))
</code></pre><p>In the example above, the version of the function that takes only one argument (so called <em>one-arity</em> or <em>1-arity</em> function)
calls another version (<em>2-arity</em>) with a default parameter. This is a common use case for multiple arities: to have default
argument values. Clojure is a hosted language and JVM (and JavaScript VMs, for that matter) does not support default argument
values, however, it does support <em>method overloading</em> and Clojure takes advantage of this.</p><p>Arities in Clojure can only differ by the number of arguments, not types. This is because Clojure is strongly dynamically typed language and type information about
parameters may or may not be available to the compiler.</p><p>A larger example:</p><pre><code class="clojure">(defn range
([]
(range 0 Double/POSITIVE_INFINITY 1))
([end]
(range 0 end 1))
([start end]
(range start end 1))
([start end step]
(comment Omitted for clarity)))
</code></pre><h2 id="destructuring-of-function-arguments">Destructuring of Function Arguments</h2><p>Sometimes function arguments are data structures: vectors, sequences, maps. To access parts of such
data structure, you may do something like this:</p><pre><code class="clojure">(defn currency-of
[m]
(let [currency (get m :currency)]
currency))
</code></pre><p>For vector arguments:</p><pre><code class="clojure">(defn currency-of
[pair]
(let [amount (first pair)
currency (second pair)]
currency))
</code></pre><p>However, this is boilerplate code that has little to do with what the function really does. Clojure
lets developer <strong>destructure</strong> parts of arguments, for both maps and sequences.</p><h3 id="positional-destructuring">Positional Destructuring</h3><p>Destructuring over vectors (<strong>positional destructuring</strong>) works like this: you replace the argument
with a vector that has "placeholders" (symbols) in positions you want to bind. For example, if the
argument is known to be a pair and you need second argument, it would look like this:</p><pre><code class="clojure">(defn currency-of
[[amount currency]]
currency)
</code></pre><p>In the example above the first element in the pair is bound to <code>amount</code> and the second one is bound to
<code>currency</code>. So far so good. However, notice that we do not use the <code>amount</code> local. In that case, we can
ignore it by replacing it with an underscore:</p><pre><code class="clojure">(defn currency-of
[[_ currency]]
currency)
</code></pre><p>Destructuring can nest (destructure deeper than one level):</p><pre><code class="clojure">(defn first-first
[[[i _] _]]
i)
</code></pre><p>While this article does not cover <code>let</code> and locals, it is worth demonstrating that positional destructuring works
exactly the same way for let bindings:</p><pre><code class="klipse-clojure nohighlight">(let [pair [10 :gbp]
[_ currency] pair]
currency)
</code></pre><h3 id="map-destructuring">Map Destructuring</h3><p>Destructuring over maps and records (<strong>map destructuring</strong>) works slightly differently:</p><pre><code class="clojure">(defn currency-of
[{currency :currency}]
currency)
</code></pre><p>In this case example, we want to bind the value for key <code>:currency</code> to <code>currency</code>. Keys don't have to be
keywords:</p><pre><code class="clojure">(defn currency-of
[{currency "currency"}]
currency)
</code></pre><pre><code class="clojure">(defn currency-of
[{currency 'currency}]
currency)
</code></pre><p>When destructuring multiple keys at once, it is more convenient to use a slightly different syntax:</p><pre><code class="clojure">(defn currency-of
[{:keys [currency amount]}]
currency)
</code></pre><p>The example above assumes that map keys will be keywords and we are interested in two values: <code>currency</code>
and <code>amount</code>. The same can be done for strings:</p><pre><code class="clojure">(defn currency-of
[{:strs [currency amount]}]
currency)
</code></pre><p>and symbols:</p><pre><code class="clojure">(defn currency-of
[{:syms [currency amount]}]
currency)
</code></pre><p>In practice, keywords are very commonly used for map keys so destructuring with <code>{:keys [...]}</code> is very common
as well.</p><p>Map destructuring also lets us specify default values for keys that may be missing:</p><pre><code class="clojure">(defn currency-of
[{:keys [currency amount] :or {currency :gbp}}]
currency)
</code></pre><p>This is very commonly used for implementing functions that take "extra options" (faking named arguments support).</p><p>Just like with positional destructuring, map destructuring works exactly the same way for let bindings:</p><pre><code class="klipse-clojure nohighlight">(let [money {:currency :gbp :amount 10}
{currency :currency} money]
currency)
</code></pre><h2 id="variadic-functions">Variadic Functions</h2><p>Variadic functions are functions that take varying number of arguments (some arguments are optional). Two examples
of such function in <code>clojure.core</code> are <code>clojure.core/str</code> and <code>clojure.core/format</code>:</p><pre><code class="klipse-clojure nohighlight">(str "a" "b")
; ⇒ "ab"
</code></pre><pre><code class="klipse-clojure nohighlight">(str "a" "b" "c")
; ⇒ "abc"
</code></pre><pre><code class="klipse-clojure nohighlight">(format "Hello, %s" "world")
; ⇒ "Hello, world"
</code></pre><pre><code class="klipse-clojure nohighlight">(format "Hello, %s %s" "Clojure" "world")
; ⇒ "Hello, Clojure world"
</code></pre><p>To define a variadic function, prefix optional arguments with an ampersand (<code>&amp;</code>):</p><pre><code class="clojure">(defn log
[message &amp; args]
(comment ...))
</code></pre><p>In the example above, one argument is required and the rest is optional. Variadic functions
are invoked as usual:</p><pre><code class="klipse-clojure nohighlight">(defn log
[message &amp; args]
(println "args: " args))
(log "message from " "192.0.0.76")
</code></pre><pre><code class="klipse-clojure nohighlight">(log "message from " "192.0.0.76" "service:xyz")
</code></pre><p>As you can see, optional arguments (<code>args</code>) are packed into a list.</p><h3 id="extra-arguments-aka-named-parameters">Extra Arguments (aka Named Parameters)</h3><p>Named parameters are achieved through the use of destructuring a variadic function.</p><p>Approaching named parameters from the standpoint of destructuring a variadic function allows for more clearly readable function invocations. This is an example of named parameters:</p><pre><code class="klipse-clojure nohighlight">(defn job-info
[&amp; {:keys [name job income] :or {job "unemployed" income "$0.00"}}]
(if name
[name job income]
(println "No name specified")))
</code></pre><p>Using the function looks like this:</p><pre><code class="klipse-clojure nohighlight">(job-info :name "Robert" :job "Engineer")
;; ["Robert" "Engineer" "$0.00"]
</code></pre><pre><code class="klipse-clojure nohighlight">(job-info :job "Engineer")
;; No name specified
</code></pre><p>Without the use of a variadic argument list, you would have to call the function with a single map argument such as <code>{:name "Robert" :job "Engineer}</code>.</p><p>Keyword default values are assigned by use of the <code>:or</code> keyword followed by a map of keywords to their default value.
Keywords not present and not given a default will be nil.</p><h2 id="higher-order-functions">Higher Order Functions</h2><p>Higher-order functions (<em>HOFs</em>) are functions that take other functions as arguments. HOFs
are an important functional programming technique and are quite commonly used in Clojure. One example
of an HOF is a function that takes a function and a collection and returns a collection of elements
that satisfy a condition (a predicate). In Clojure, this function is called <code>clojure.core/filter</code>:</p><pre><code class="klipse-clojure nohighlight">(filter even? (range 0 10)) ; ⇒ (0 2 4 6 8)
</code></pre><p>In the example above, <code>clojure.core/filter</code> takes <code>clojure.core/even?</code> as an argument.</p><p><code>clojure.core</code> has dozens of other higher-order functions. The most commonly used ones are covered in <a href="../core_overview/index.html">clojure.core Overview</a>.</p><h2 id="private-functions">Private Functions</h2><p>Functions in Clojure can be private to their namespace.</p><p>They are covered in more detail in the <a href="../namespaces/index.html">Namespaces</a> guide.</p><h2 id="keywords-as-functions">Keywords as Functions</h2><p>In Clojure, keywords can be used as functions. They take a map or record and look themselves up in it:</p><pre><code class="klipse-clojure nohighlight">(:age {:age 27 :name "Michael"})
; ⇒ 27
</code></pre><p>This is commonly used with higher order functions:</p><pre><code class="klipse-clojure nohighlight">(map :age [{:age 45 :name "Joe"}
{:age 42 :name "Jill"}
{:age 17 :name "Matt"}])
;; ⇒ (45 42 17)
</code></pre><p>and the <code>-&gt;</code> macro:</p><pre><code class="klipse-clojure nohighlight">(-&gt; [{:age 45 :name "Joe"} {:age 42 :name "Jill"}]
first
:name)
;; ⇒ "Joe"
</code></pre><h2 id="maps-as-functions">Maps as Functions</h2><p>Clojure maps are also functions that take keys and look up values for them:</p><pre><code class="klipse-clojure nohighlight">({:age 42 :name "Joe"} :name)
; ⇒ "Joe"
</code></pre><pre><code class="klipse-clojure nohighlight">({:age 42 :name "Joe"} :age)
; ⇒ 42
</code></pre><pre><code class="klipse-clojure nohighlight">({:age 42 :name "Joe"} :unknown)
; ⇒ nil
</code></pre><p>Note that this is <strong>not true</strong> for Clojure records, which are almost identical to maps in other
cases.</p><h2 id="sets-as-functions">Sets as Functions</h2><pre><code class="klipse-clojure nohighlight">(#{1 2 3} 1)
; ⇒ 1
</code></pre><pre><code class="klipse-clojure nohighlight">(#{1 2 3} 10)
; ⇒ nil
</code></pre><pre><code class="klipse-clojure nohighlight">(#{:us :au :ru :uk} :uk)
; ⇒ :uk
</code></pre><pre><code class="klipse-clojure nohighlight">(#{:us :au :ru :uk} :cn)
; ⇒ nil
</code></pre><p>This is often used to check if a value is in a set:</p><pre><code class="clojure">(when (countries :in)
(comment ...))
(if (countries :in)
(comment Implement positive case)
(comment Implement negative case))
</code></pre><p>because everything but <code>false</code> and <code>nil</code> evaluates to <code>true</code> in Clojure.</p><h2 id="clojure-functions-as-comparators">Clojure Functions As Comparators</h2><p>Clojure functions implement the <a href="http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html">java.util.Comparator</a>
interface and can be used as comparators.</p><h2 id="wrapping-up">Wrapping Up</h2><p>Functions are at the heart of Clojure. They are defined using the <code>defn</code> macro, can have multiple arities,
be variadic and support parameter destructuring. Function arguments and return value can optionally be
type hinted.</p><p>Functions are first class values and can be passed to other functions (called Higher Order Functions or HOFs).
This is fundamental to functional programming techniques.</p><p>Several core data types behave like functions. When used reasonably, this can lead to more concise, readable
code.</p><h2 id="contributors">Contributors</h2><p>Michael Klishin <a href="mailto:michael@defprotocol.org">michael@defprotocol.org</a>, 2012 (original author)</p>
<div id="prev-next">
<a href="../collections_and_sequences/index.html">&laquo; Collections and Sequences in Clojure</a>
||
<a href="../laziness/index.html">Laziness in Clojure &raquo;</a>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div id="sidebar">
<h3>Links</h3>
<ul id="links">
<li><a href="../../about/index.html">About</a></li>
<li><a href="../../content/index.html">Table of Contents</a></li>
<li><a href="../../tutorials/getting_started/index.html">Getting Started with Clojure</a></li>
<li><a href="../../tutorials/introduction/index.html">Introduction to Clojure</a></li>
<li><a href="../../tutorials/emacs/index.html">Clojure with Emacs</a></li>
<li><a href="../../tutorials/vim_fireplace/index.html">Clojure with Vim and fireplace.vim</a></li>
<li><a href="../../tutorials/eclipse/index.html">Starting with Eclipse and Counterclockwise For Clojure Development</a></li>
<li><a href="../../tutorials/basic_web_development/index.html">Basic Web Development</a></li>
<li><a href="../../tutorials/parsing_xml_with_zippers/index.html">Parsing XML in Clojure</a></li>
<li><a href="../../tutorials/growing_a_dsl_with_clojure/index.html">Growing a DSL with Clojure</a></li>
<li><a href="../core_overview/index.html">Overview of clojure.core, the standard Clojure library</a></li>
<li><a href="../namespaces/index.html">Clojure Namespaces and Vars</a></li>
<li><a href="../collections_and_sequences/index.html">Collections and Sequences in Clojure</a></li>
<li><a href="index.html">Functions in Clojure</a></li>
<li><a href="../laziness/index.html">Laziness in Clojure</a></li>
<li><a href="../interop/index.html">Clojure interoperability with Java</a></li>
<li><a href="../macros/index.html">Clojure Macros and Metaprogramming</a></li>
<li><a href="../polymorphism/index.html">Polymorphism in Clojure: Protocols and Multimethods</a></li>
<li><a href="../concurrency_and_parallelism/index.html">Concurrency and Parallelism in Clojure</a></li>
<li><a href="../glossary/index.html">Clojure Terminology Guide</a></li>
<li><a href="../../ecosystem/libraries_directory/index.html">A Directory of Clojure Libraries</a></li>
<li><a href="../../ecosystem/libraries_authoring/index.html">Library Development and Distribution</a></li>
<li><a href="../../ecosystem/generating_documentation/index.html">Generating Documentation</a></li>
<li><a href="../../ecosystem/data_processing/index.html">Data Processing (Help Wanted)</a></li>
<li><a href="../../ecosystem/web_development/index.html">Web Development (Overview)</a></li>
<li><a href="../../ecosystem/maven/index.html">How to use Maven to build Clojure projects</a></li>
<li><a href="../../ecosystem/community/index.html">Clojure Community</a></li>
<li><a href="../../ecosystem/user_groups/index.html">Clojure User Groups</a></li>
<li><a href="../../ecosystem/running_cljug/index.html">Running a Clojure User Group</a></li>
<li><a href="../../ecosystem/books/index.html">Books about Clojure and ClojureScript</a></li>
<li><a href="../../cookbooks/data_structures/index.html">Data Structures (Help wanted)</a></li>
<li><a href="../../cookbooks/strings/index.html">Strings</a></li>
<li><a href="../../cookbooks/math/index.html">Mathematics with Clojure</a></li>
<li><a href="../../cookbooks/date_and_time/index.html">Date and Time (Help wanted)</a></li>
<li><a href="../../cookbooks/files_and_directories/index.html">Working with Files and Directories in Clojure</a></li>
<li><a href="../../cookbooks/middleware/index.html">Middleware in Clojure</a></li>
<li><a href="../../ecosystem/java_jdbc/home.html">java.jdbc - Getting Started</a></li>
<li><a href="../../ecosystem/java_jdbc/using_sql.html">java.jdbc - Manipulating data with SQL</a></li>
<li><a href="../../ecosystem/java_jdbc/using_ddl.html">java.jdbc - Using DDL and Metadata</a></li>
<li><a href="../../ecosystem/java_jdbc/reusing_connections.html">java.jdbc - How to reuse database connections</a></li>
<li><a href="../../ecosystem/core_typed/home/index.html">core.typed - User Documentation Home</a></li>
<li><a href="../../ecosystem/core_typed/user_documentation/index.html">core.typed - User Documentation</a></li>
<li><a href="../../ecosystem/core_typed/rationale/index.html">core.typed - Rationale</a></li>
<li><a href="../../ecosystem/core_typed/quick_guide.html">core.typed - Quick Guide</a></li>
<li><a href="../../ecosystem/core_typed/start/introduction_and_motivation/index.html">core.typed - Getting Started: Introduction and Motivation</a></li>
<li><a href="../../ecosystem/core_typed/types/index.html">core.typed - Types</a></li>
<li><a href="../../ecosystem/core_typed/start/annotations/index.html">core.typed - Annotations</a></li>
<li><a href="../../ecosystem/core_typed/poly_fn/index.html">core.typed - Polymorphic Functions</a></li>
<li><a href="../../ecosystem/core_typed/filters/index.html">core.typed - Filters</a></li>
<li><a href="../../ecosystem/core_typed/mm_protocol_datatypes/index.html">core.typed - Protocols</a></li>
<li><a href="../../ecosystem/core_typed/loops/index.html">core.typed - Looping constructs</a></li>
<li><a href="../../ecosystem/core_typed/function_types/index.html">core.typed - Functions</a></li>
<li><a href="../../ecosystem/core_typed/limitations/index.html">core.typed - Limitations</a></li>
</ul>
</div>
</div>
</div>
<footer>Copyright &copy; 2021 Multiple Authors
<p style="text-align: center;">Powered by <a href="http://cryogenweb.org">Cryogen</a></p></footer>
</div>
<script src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="../../../js/highlight.pack.js" type="application/javascript"></script>
<script>hljs.initHighlightingOnLoad();</script>
<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/app.klipse.tech/css/codemirror.css">
<script>
window.klipse_settings = {
"selector" : ".klipse-clojure"
};
</script>
<script src="https://storage.googleapis.com/app.klipse.tech/plugin/js/klipse_plugin.js"></script>
</body>
</html>