├── .gitignore ├── images ├── fg.png ├── agh.png ├── atop.png ├── fgh.png ├── over.png ├── beside.png ├── commute.png └── train45.png ├── README.md ├── LICENSE ├── New in v15.ipynb ├── working introduction ├── 05 - e) APL Errors.ipynb ├── 16 - n) Decisions and “Canonical” Function Definition.ipynb ├── 10 - h) Direct Definition of Functions.ipynb ├── 02 - b) Experiments.ipynb ├── 03 - c) More Experiments.ipynb ├── 13 - k) Replace and Fill.ipynb ├── 09 - g) Order of Evaluation.ipynb ├── 04 - d) Characters (Text).ipynb ├── 15 - m) Parameters — Global Variables vs Arguments.ipynb ├── 01 - a) Names and Expressions.ipynb ├── 07 - f) More characters, Names, and Structure.ipynb ├── 11 - i) Numbers, Numeric Text, and Formatted Data.ipynb └── 14 - l) Reading APL Expressions.ipynb ├── New in v17.ipynb ├── Using the TryAPL Tutorials.ipynb ├── Random Numbers.ipynb ├── Lookup Without Replacement.ipynb ├── Grading and Sorting.ipynb ├── Reduce and Scan.ipynb ├── Arithmetic Functions.ipynb ├── New in v16.ipynb ├── APL Expressions.ipynb └── Conway's Game of Life.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ 2 | -------------------------------------------------------------------------------- /images/fg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/fg.png -------------------------------------------------------------------------------- /images/agh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/agh.png -------------------------------------------------------------------------------- /images/atop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/atop.png -------------------------------------------------------------------------------- /images/fgh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/fgh.png -------------------------------------------------------------------------------- /images/over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/over.png -------------------------------------------------------------------------------- /images/beside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/beside.png -------------------------------------------------------------------------------- /images/commute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/commute.png -------------------------------------------------------------------------------- /images/train45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/dyalog-jupyter-notebooks/HEAD/images/train45.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Jupyter](http://jupyter.org/) notebooks for [Dyalog APL](https://www.dyalog.com/) 2 | 3 | ## What is this and how do I use it? 4 | 5 | Please see [our wiki](https://github.com/Dyalog/dyalog-jupyter-kernel/wiki). 6 | 7 | ## Where is the language kernel? 8 | 9 | A kernel for using these notebooks is available [here](https://github.com/Dyalog/dyalog-jupyter-kernel). 10 | 11 | ## Contributing 12 | 13 | Feel free to contribute additional notebooks to our collection through emailing notebooks@dyalog.com or submitting [pull requests](https://help.github.com/articles/about-pull-requests/). 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dyalog Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /New in v15.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Monadic function `∪/`\n", 8 | "*Catenate reduction* works on empty arrays, and gives an empty result with a prototype appropriate to the empty argument:" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "data": { 18 | "text/html": [ 19 | "┌─────┐\n", 20 | "│ ┌⊖┐ │\n", 21 | "│ │0│ │\n", 22 | "│ └~┘ │\n", 23 | "└∊────┘\n", 24 | "" 25 | ] 26 | }, 27 | "execution_count": 1, 28 | "metadata": {}, 29 | "output_type": "execute_result" 30 | } 31 | ], 32 | "source": [ 33 | "]display ,/⍬" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 2, 39 | "metadata": {}, 40 | "outputs": [ 41 | { 42 | "data": { 43 | "text/html": [ 44 | "┌─────────────────┐\n", 45 | "│ ┌⊖────────────┐ │\n", 46 | "│ │ ┌→────────┐ │ │\n", 47 | "│ │ │ ┌⊖┐ ┌⊖┐ │ │ │\n", 48 | "│ │ │ │ │ │ │ │ │ │\n", 49 | "│ │ │ └─┘ └─┘ │ │ │\n", 50 | "│ │ └∊────────┘ │ │\n", 51 | "│ └∊────────────┘ │\n", 52 | "└∊────────────────┘\n", 53 | "" 54 | ] 55 | }, 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "output_type": "execute_result" 59 | } 60 | ], 61 | "source": [ 62 | "]display ,/0⍴⊂⊂'' ''" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "### Other enhancements\n", 70 | "\n", 71 | "Version 15.0 introduced a family of system functions to handle native files, especially Unicode files, in a manner as easy as possible. However, creating and modifying files in the file system is inappropriate for a tutorial like this. You may instead find information about this in the [release notes](http://help.dyalog.com/15.0/Content/RelNotes15.0/Key%20Features.htm)." 72 | ] 73 | } 74 | ], 75 | "metadata": { 76 | "kernelspec": { 77 | "display_name": "Dyalog APL", 78 | "language": "apl", 79 | "name": "dyalog-kernel" 80 | }, 81 | "language_info": { 82 | "file_extension": ".apl", 83 | "mimetype": "text/apl", 84 | "name": "APL" 85 | }, 86 | "tryapl": { 87 | "category": "Highlights of Recent Releases", 88 | "description": "Language extensions in Dyalog APL version 15.0", 89 | "name": "New in version 15.0" 90 | } 91 | }, 92 | "nbformat": 4, 93 | "nbformat_minor": 2 94 | } 95 | -------------------------------------------------------------------------------- /working introduction/05 - e) APL Errors.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "If an expression entered in **APL** contains an error -- i.e., something that APL can't make sense of, -- it will display a message indicating what sort of problem it had, and repeat the input line with a caret underneath to indicate where (proceeding right to left) it encountered the problem." 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "A `SYNTAX ERROR` is an error in the way the elements of the language are combined, like a grammatical mistake in English." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "oops←'this lacks a closing quote" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "In this case, an opening quote without a closing quote lacks meaning." 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "Another common error is a `VALUE ERROR`, using a name which has not yet been assigned to any value. A `VALUE ERROR` is often the result of a typing error." 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "value←'priceless'\n", 47 | "value" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "A `DOMAIN ERROR` occurs when a function is applied to an argument outside if its domain. For instance `+` cannot act on character vectors:" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "'one'+'one'" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "When a function is applied two vectors, you can get a `LENGTH ERROR`." 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "1 2+4 5 6" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "The left argument has two elements, while the right argument has three. There is no way to pair them up" 87 | ] 88 | } 89 | ], 90 | "metadata": { 91 | "kernelspec": { 92 | "display_name": "Dyalog APL", 93 | "language": "apl", 94 | "name": "dyalog-kernel" 95 | }, 96 | "language_info": { 97 | "file_extension": ".apl", 98 | "mimetype": "text/apl", 99 | "name": "APL" 100 | }, 101 | "tryapl": { 102 | "category": "Introductory Course", 103 | "description": "How APL deals with problems", 104 | "name": "Lesson 05: e) APL Errors" 105 | } 106 | }, 107 | "nbformat": 4, 108 | "nbformat_minor": 2 109 | } 110 | -------------------------------------------------------------------------------- /New in v17.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Monadic function `∪`\n", 8 | "*Unique* works on major cells:" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "data": { 18 | "text/html": [ 19 | "2 7\n", 20 | "1 8\n", 21 | "2 8\n", 22 | "1 8\n", 23 | "2 8\n", 24 | "4 5\n", 25 | "" 26 | ] 27 | }, 28 | "execution_count": 1, 29 | "metadata": {}, 30 | "output_type": "execute_result" 31 | } 32 | ], 33 | "source": [ 34 | "matrix←6 2⍴2 7 1 8 2 8 1 8 2 8 4 5\n", 35 | "matrix" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/html": [ 46 | "2 7\n", 47 | "1 8\n", 48 | "2 8\n", 49 | "4 5\n", 50 | "" 51 | ] 52 | }, 53 | "execution_count": 2, 54 | "metadata": {}, 55 | "output_type": "execute_result" 56 | } 57 | ], 58 | "source": [ 59 | "∪matrix" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "### Dyadic function `⍸` and monadic functions `⍋` and `⍒`\n", 67 | "*Interval index*, *Grade up*, and *Grade down* use [Total Array Ordering](https://www.youtube.com/watch?v=8cbPLRAcC7M&t=6m47s) to work on the major cells:" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 3, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "data": { 77 | "text/html": [ 78 | "0 2 2\n", 79 | "3 3 3\n", 80 | "" 81 | ] 82 | }, 83 | "execution_count": 3, 84 | "metadata": {}, 85 | "output_type": "execute_result" 86 | } 87 | ], 88 | "source": [ 89 | "'Adam' 'Jay' 'Roger'⍸2 3⍴'APLXYZ' ⍝ scalars of a vector" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "data": { 99 | "text/html": [ 100 | "2 1\n", 101 | "" 102 | ] 103 | }, 104 | "execution_count": 4, 105 | "metadata": {}, 106 | "output_type": "execute_result" 107 | } 108 | ], 109 | "source": [ 110 | "(3 5⍴'Adam Jay Roger')⍸2 5⍴'KarenGitte' ⍝ vectors of a matrix" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 5, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "data": { 120 | "text/html": [ 121 | "3 6 1 2 5 4\n", 122 | "" 123 | ] 124 | }, 125 | "execution_count": 5, 126 | "metadata": {}, 127 | "output_type": "execute_result" 128 | } 129 | ], 130 | "source": [ 131 | "vector←0 0J2 ¯1 'A' 1 0J¯2\n", 132 | "⍋vector" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 6, 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "data": { 142 | "text/html": [ 143 | "¯1 0J¯2 0 0J2 1 A\n", 144 | "" 145 | ] 146 | }, 147 | "execution_count": 6, 148 | "metadata": {}, 149 | "output_type": "execute_result" 150 | } 151 | ], 152 | "source": [ 153 | "{(⊂⍋⍵)⌷⍵}vector ⍝ new special-cased idiom" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 7, 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/html": [ 164 | "A 1 0J2 0 0J¯2 ¯1\n", 165 | "" 166 | ] 167 | }, 168 | "execution_count": 7, 169 | "metadata": {}, 170 | "output_type": "execute_result" 171 | } 172 | ], 173 | "source": [ 174 | "{(⊂⍒⍵)⌷⍵}vector ⍝ new special-cased idiom" 175 | ] 176 | } 177 | ], 178 | "metadata": { 179 | "kernelspec": { 180 | "display_name": "Dyalog APL", 181 | "language": "apl", 182 | "name": "dyalog-kernel" 183 | }, 184 | "language_info": { 185 | "file_extension": ".apl", 186 | "mimetype": "text/apl", 187 | "name": "APL" 188 | }, 189 | "tryapl": { 190 | "category": "Highlights of Recent Releases", 191 | "description": "Language extensions in Dyalog APL version 17.0", 192 | "name": "New in version 17.0" 193 | } 194 | }, 195 | "nbformat": 4, 196 | "nbformat_minor": 2 197 | } 198 | -------------------------------------------------------------------------------- /working introduction/16 - n) Decisions and “Canonical” Function Definition.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Most programs need to “make decisions”, i.e., to select among different courses of action depending on some condition, some element or property of the data being processed, e.g., user input or the contents of a web page. The first example in this lesson implements a simple choice." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 5, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "]dinput\n", 17 | "SumParity←{\n", 18 | " 0=2|t←+/,⍵:'even'\n", 19 | " 0=1|t:'odd'\n", 20 | " 'non-integer'\n", 21 | "}" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 9, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/html": [ 32 | "{ \n", 33 | " 0=2|t←+/,⍵:'even'\n", 34 | " 0=1|t:'odd' \n", 35 | " 'non_integer' \n", 36 | " } \n", 37 | "" 38 | ] 39 | }, 40 | "execution_count": 9, 41 | "metadata": {}, 42 | "output_type": "execute_result" 43 | } 44 | ], 45 | "source": [ 46 | "SumParity" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "Next is **recursion**, which builds a result by a function repeatedly calling itself until some terminating condition is met. `MultiPrompt` takes as its argument a vector of separate prompt texts and uses the function `Prompt` to present them one at a time and build up a corresponding vector of responses." 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 16, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "Prompt←{⍞}" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 16, 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "]dinput\n", 72 | "MultiPrompt←{\n", 73 | " ⍝ ⍵ should be a vector of text vectors\n", 74 | " 0∊⍴⍵:⍬\n", 75 | " (⊂Prompt⊃¯1↑⍵),⍨MultiPrompt ¯1↓⍵\n", 76 | "}" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 17, 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "name": "stderr", 86 | "output_type": "stream", 87 | "text": [ 88 | "JUPYTER NOTEBOOK: Input through ⍞ is not supported" 89 | ] 90 | } 91 | ], 92 | "source": [ 93 | "txt←⊂'What is your favorite '\n", 94 | "txt←txt,¨'colour?' 'number?' 'food?'\n", 95 | "⍴t←MultiPrompt txt" 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "Dynamically defined functions don’t lend themselves to some sorts of flow control, loops and block-structured code in particular. There is another form, **canonical** function definition, which can be used effectively in such cases. In fact, canonically defined functions are just as versatile as dynamically defined functions, though the two forms handle decision-making differently. Rather than the guards of dynamic functions, canonical functions use block structures delimited by control words to direct program flow." 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 6, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "∇r←SumParity_c arg;t\n", 112 | " :If 0=2|t←+/,arg\n", 113 | " r←'even'\n", 114 | " :ElseIf 0=1|t\n", 115 | " r←'odd'\n", 116 | " :Else\n", 117 | " r←'non-integer'\n", 118 | " :EndIf\n", 119 | "∇" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "In canonical functions the first line, or **header**, defines function name, the function's syntax, and all local names. In the above example the function name is `SumParity_c`. It takes a single (right) argument, which is identified by the **local** name `arg`. The assignment arrow indicates that it returns a result, which is identified by the local name `r`. Unlike in dynamic functions, assignment to a name within a canonical function doesn’t automatically localize it. Instead, names are made local by listing them in the right-hand side of the header, preceding each with a semicolon. This has been done with the variable name `t` in the above function." 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "Test this function, comparing its results with the earlier `SumParity`." 134 | ] 135 | } 136 | ], 137 | "metadata": { 138 | "kernelspec": { 139 | "display_name": "Dyalog APL", 140 | "language": "apl", 141 | "name": "dyalog-kernel" 142 | }, 143 | "language_info": { 144 | "file_extension": ".apl", 145 | "mimetype": "text/apl", 146 | "name": "APL" 147 | }, 148 | "tryapl": { 149 | "category": "Introductory Course", 150 | "description": "Structured code with traditional functions", 151 | "name": "Lesson 18: n) Decisions and “Canonical” Function Definition" 152 | } 153 | }, 154 | "nbformat": 4, 155 | "nbformat_minor": 2 156 | } 157 | -------------------------------------------------------------------------------- /working introduction/10 - h) Direct Definition of Functions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "oil97←10000+6 12⍴?100000" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Dyalog APL provides four means of creating named functions. The method presented here gives the best combination of simplicity and power for most programming needs. Functions defined in this way are known as **dynamic functions** (for reasons which need not concern us yet)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "Define a function that rounds a number:" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "R←{⌊0.5+⍵}" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "R" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "R 12 13 14÷3" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "Using the rules for order of evaluation and the meanings of `⍺` and `⍵`, explain to yourself what the function `At` does:" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "At←{(1+⍵÷100)*⍺}" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "SquareRoot←{⍵*0.5}" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "This shorter name is one commonly used:" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "Sqrt←{SquareRoot ⍵}" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "Beeline←{Sqrt (⍺*2)+(⍵*2)}" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": null, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "Hypotenuse←Beeline" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "Compare `Sqrt` and `Hypotenuse` with `SquareRoot` and `Beeline`.\n", 117 | "\n", 118 | "How do these pairs differ from each other, and why?" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "A useful procedure for developing function definitions is the following:\n", 126 | "\n", 127 | "1. Select or construct some sample values for which the result of applying the desired function is known.\n", 128 | "2. Define a function that contains an expression expected to give this result from the test data.\n", 129 | "3. If the result is incorrect, revise the function to correct the error.\n", 130 | "4. Repeat 2. and 3. as needed." 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "As an example, we can try to define a function `Rowsums`, to yield the sums of the rows when applied to a matrix of numbers. The matrix `oil97`, which gives United States oil imports from each of six “countries” (5 countries and “Other”, i.e., all the rest) for each month of the\n", 138 | "year 1997, can be used as test data.\n", 139 | "\n", 140 | "Here is the first try:" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "Rowsums←{+/[1]⍵}\n", 150 | "result←Rowsums oil97" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": null, 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "≢result" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "`result` has 12 elements, but that can't be right, because `oil97` has 12 columns, but only 6 rows." 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "To fix it, we change the axis:" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "Rowsums←{+/[2]⍵}" 183 | ] 184 | } 185 | ], 186 | "metadata": { 187 | "kernelspec": { 188 | "display_name": "Dyalog APL", 189 | "language": "apl", 190 | "name": "dyalog-kernel" 191 | }, 192 | "language_info": { 193 | "file_extension": ".apl", 194 | "mimetype": "text/apl", 195 | "name": "APL" 196 | }, 197 | "tryapl": { 198 | "category": "Introductory Course", 199 | "description": "User defined functions in the \"dfn\" format", 200 | "name": "Lesson 10: h) Direct Definition of Functions" 201 | } 202 | }, 203 | "nbformat": 4, 204 | "nbformat_minor": 2 205 | } 206 | -------------------------------------------------------------------------------- /working introduction/02 - b) Experiments.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "It is often easiest to gain an understanding of a function or expression by using it in a few examples, and then briefly formulating what it does. For each expression below, see if you can describe the point that it illustrates. For example:" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "⍳10" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "The function `⍳` produces a sequence of positive integers up to its argument" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | ".2×⍳10" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "`S×⍳N` returns a sequence of N elements, each S greater than the previous" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "Execute the lines below. Change values, experiment and then describe what the line does." 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "3+0.2×⍳10" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "series←⍳6\n", 65 | "table←2 3⍴series" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "To view the values `series` and `table`, enter either of their names and execute" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "series×series" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "table×table" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "2×table" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "seriesoftables←2 3 4⍴⍳24" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "5⍴1 0" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "5 5⍴1 0" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "4 4⍴1 0 0 0 0" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "⍴series" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "⍴table" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "⍴seriesoftables" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "series,7 8" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": null, 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [ 180 | "6-⍳11" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "¯2×(6-⍳11)" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "### Terminology\n", 197 | "\n", 198 | "The symbols `×` and `*`, cross and star, denote the functions **times** and **exponentiation**. When one reads APL expressions, it is best to use the name of the function denoted, rather than the name of the symbol, e.g., \"three times four\" rather than \"three cross four\"\n", 199 | "\n", 200 | "This aids understanding when a function has both monadic (one argument) and dyadic (two arguments) meanings, such as `⍴` (the Greek letter *rho*) in the above examples. The expression `2 3⍴series` should normally be read as \"2 3 reshape (of) series\" rather than \"2 3 rho series\", while `⍴series` should be read as \"shape (of) series\", not \"rho series\". And `series,7 8` should be read as \"series catenated with 7 8\", or just \"series with 7 8\", but not \"series comma 7 8\".\n", 201 | "\n", 202 | "Learning the functions' names instead of -- or together with -- the symbols' names makes it easier to both understand and talk about APL expressions." 203 | ] 204 | } 205 | ], 206 | "metadata": { 207 | "kernelspec": { 208 | "display_name": "Dyalog APL", 209 | "language": "apl", 210 | "name": "dyalog-kernel" 211 | }, 212 | "language_info": { 213 | "file_extension": ".apl", 214 | "mimetype": "text/apl", 215 | "name": "APL" 216 | }, 217 | "tryapl": { 218 | "category": "Introductory Course", 219 | "description": "Learn APL through experimentation", 220 | "name": "Lesson 02: b) Experiments" 221 | } 222 | }, 223 | "nbformat": 4, 224 | "nbformat_minor": 2 225 | } 226 | -------------------------------------------------------------------------------- /working introduction/03 - c) More Experiments.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "To start with, we'll get back our variables from the last lesson." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "series←⍳6\n", 17 | "table←2 3⍴series\n", 18 | "seriesoftables←2 3 4⍴⍳24" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "For each expression below, describe what it does. If necessary, consult the hints which follow certain groups of expressions:" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "+/series" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "⌈/series" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "⌈/3 1 4 2" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "⌊/series" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "+/[1]table" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "+/[2]table" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "a←seriesoftables" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "+/[1]a" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "+/[2]a" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "+/[3]a" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "**HINT**: Examine the shapes of the arguments and results, i.e., `⍴A` and `⍴+/[1] A`, etc." 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "series,series" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "table,[1]table" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "table,[2]table" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "If the axis specification is omitted, the function is always applied along the **last axis**, i.e. the rows:" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "table,table" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "a,[1]a" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "a,[2]a" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "a,[3]a" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "In 3-D array, the last axis is the third. In a matrix (2-dimensional array) such as `table`, it is the second." 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "a,a" 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "metadata": {}, 214 | "source": [ 215 | "Vectors are 1-dimensional, so this also works, but the `[1]` is unnecessary" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": null, 221 | "metadata": {}, 222 | "outputs": [], 223 | "source": [ 224 | "series,[1]series" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": {}, 230 | "source": [ 231 | "Execute `?6` several times and try to determine the use of the question mark. Then enter expressions such as `2 3⍴9` and `M←?2 3⍴9` to see how it applies to a **matrix** (table)." 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "?6" 241 | ] 242 | } 243 | ], 244 | "metadata": { 245 | "kernelspec": { 246 | "display_name": "Dyalog APL", 247 | "language": "apl", 248 | "name": "dyalog-kernel" 249 | }, 250 | "language_info": { 251 | "file_extension": ".apl", 252 | "mimetype": "text/apl", 253 | "name": "APL" 254 | }, 255 | "tryapl": { 256 | "category": "Introductory Course", 257 | "description": "Learn more APL through experimentation", 258 | "name": "Lesson 03: c) More Experiments" 259 | } 260 | }, 261 | "nbformat": 4, 262 | "nbformat_minor": 2 263 | } 264 | -------------------------------------------------------------------------------- /working introduction/13 - k) Replace and Fill.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Now is the time for substituting existing data." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "t←'parrot'" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "t[1]←'c'" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "t" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "t←⍳5" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "t[4 2]←3 1" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "t" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "t←'mother' 'father' 'child'" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "(3⊃t)←'daughter'" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "t" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "t[3]←⊂'son'" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "t" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "t←⍳5" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "In theory, any selection on a single variable can be used to the left of the assignment arrow to produce selective assignment." 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "(1 0 1/2↓t)←100 200" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "t" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "In fact, Dyalog APL supports many complex selections for assignment:" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "(1 0 1/t[3 4 5])←67 53" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "t" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "metadata": {}, 171 | "source": [ 172 | "A couple of APL primitive functions create additional, **fill elements**" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "8↑⍳5" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "When the left argument to `↑` specifies taking more than is there, it’s known as **overtake**." 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": null, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "¯9↑'spaces'" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": null, 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [ 206 | "mat←5 5⍴⍳25" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "metadata": {}, 213 | "outputs": [], 214 | "source": [ 215 | "7 7↑¯6 ¯6↑mat" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": {}, 221 | "source": [ 222 | "The zeros in the left argument to **expand** specify where to insert **fill elements**:" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": null, 228 | "metadata": {}, 229 | "outputs": [], 230 | "source": [ 231 | "1 0 1 0 1 0 1\\'abcd'" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "1 0 1 0 0 1 0 0 0 1\\⍳4" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [ 249 | "1 0 1 0 1\\[1]3 3⍴'JanPatSue'" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "metadata": {}, 256 | "outputs": [], 257 | "source": [ 258 | "exp←1 0 1 0 1" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": {}, 265 | "outputs": [], 266 | "source": [ 267 | "t←exp\\[1]3 3⍴'JanPatSue'" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": null, 273 | "metadata": {}, 274 | "outputs": [], 275 | "source": [ 276 | "((~exp)/[1]t)←'*'" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": null, 282 | "metadata": {}, 283 | "outputs": [], 284 | "source": [ 285 | "t" 286 | ] 287 | } 288 | ], 289 | "metadata": { 290 | "kernelspec": { 291 | "display_name": "Dyalog APL", 292 | "language": "apl", 293 | "name": "dyalog-kernel" 294 | }, 295 | "language_info": { 296 | "file_extension": ".apl", 297 | "mimetype": "text/apl", 298 | "name": "APL" 299 | }, 300 | "tryapl": { 301 | "category": "Introductory Course", 302 | "description": "Changing and adding default data", 303 | "name": "Lesson 13: k) Replace and Fill" 304 | } 305 | }, 306 | "nbformat": 4, 307 | "nbformat_minor": 2 308 | } 309 | -------------------------------------------------------------------------------- /Using the TryAPL Tutorials.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Welcome to the TryAPL tutorial system\n", 8 | "Press the Enter ↵ key or click on the *next* button ⇨ to progress through a notebook." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "These tutorials are [Jupyter notebooks](https://jupyter.org/#about-notebook) using [the Dyalog APL kernel](https://github.com/Dyalog/dyalog-jupyter-kernel/wiki). They can be downloaded from the [Dyalog Jupyter notebook repository](https://github.com/Dyalog/dyalog-jupyter-notebooks/).\n", 16 | "\n", 17 | "First we'll cover how to use the interface; which buttons and keys to press etc. \n", 18 | "Then we'll cover the current features and limitations of the TryAPL Jupyter system, compared to full Jupyter notebook system with the Dyalog kernel installed." 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "## TryAPL Jupyter Interface" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "Click the *Previous step* button ⇦ to go back one step within a notebook." 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "Press the *Restart notebook* button ↺ to start a notebook from the beginning. " 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "Press *Stop notebook* 🏠︎ to return to the *LEARN* menu." 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "When a notebook has an APL code block, that code will be copied into the session-pane on the right hand side of TryAPL and executed. " 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "Single-line expressions can be modified and re-executed in TryAPL." 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 1, 66 | "metadata": {}, 67 | "outputs": [ 68 | { 69 | "data": { 70 | "text/html": [ 71 | "2 3 5 7\n", 72 | "" 73 | ] 74 | }, 75 | "execution_count": 1, 76 | "metadata": {}, 77 | "output_type": "execute_result" 78 | } 79 | ], 80 | "source": [ 81 | "{⍸2=+⌿0=∘.|⍨⍳⍵}10" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "Clicking on purple code block text in the left pane will insert it into the right pane, replacing the current line." 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "The session is like a text editor. You can go up and edit any text in the right-hand pane, then press Enter to execute the code on that line." 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "Cycle back through manually entered expressions with Ctrl+Shift+Backspace" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "Cycle forward with Ctrl+Shift+Enter" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "## Features and Limitations" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "#### Dyalog APL and the Jupyter kernel" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "The following features are currently available in the Dyalog Jupyter kernel but will not work on TryAPL.\n", 131 | "- Multiline dfns using the `]dinput` user command\n", 132 | "- Tradfns\n", 133 | "- Rendering HTML with the `]html` user command\n", 134 | "- Making quick plots using the `]plot` user command\n", 135 | "- Classes, Namespaces and JSON Objects" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "#### Markdown" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "Currently, TryAPL renders standard markdown using the [marked.js](https://github.com/markedjs/marked) library.\n", 150 | "\n", 151 | "To embed examples, we allow inline code `+/⍳10` like this.\n", 152 | "\n", 153 | "Or whole code blocks\n", 154 | "\n", 155 | "```APL\n", 156 | "+/⍳10\n", 157 | "```\n", 158 | "\n", 159 | "like this." 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "Of course, it is best to keep code in the executable code blocks" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 2, 172 | "metadata": {}, 173 | "outputs": [ 174 | { 175 | "data": { 176 | "text/html": [ 177 | "55\n", 178 | "" 179 | ] 180 | }, 181 | "execution_count": 2, 182 | "metadata": {}, 183 | "output_type": "execute_result" 184 | } 185 | ], 186 | "source": [ 187 | "+/⍳10 ⍝ Like this" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "TryAPL also renders [LaTeX](https://www.latex-project.org/) using [MathJax](https://www.mathjax.org/). \n", 195 | "So for example, we can say $\\sum_{n=1}^{N} n $ is equivalent to `+/⍳N` inline.\n", 196 | "\n", 197 | "Or we can use blocks:\n", 198 | "$$\\sum_{n=1}^{N}n$$\n", 199 | "```APL\n", 200 | "+/⍳N\n", 201 | "```" 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": {}, 207 | "source": [ 208 | "TryAPL doesn't currently support images with relative URLs, but does support absolute URLs.\n", 209 | "\n", 210 | "" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "We welcome submissions of notebooks for inclusion in Try APL, as well as reports of anomalies, suggestions, criticisms, and comments to tryapl@dyalog.com." 218 | ] 219 | } 220 | ], 221 | "metadata": { 222 | "kernelspec": { 223 | "display_name": "Dyalog APL", 224 | "language": "apl", 225 | "name": "dyalog-kernel" 226 | }, 227 | "language_info": { 228 | "file_extension": ".apl", 229 | "mimetype": "text/apl", 230 | "name": "APL" 231 | } 232 | }, 233 | "nbformat": 4, 234 | "nbformat_minor": 2 235 | } 236 | -------------------------------------------------------------------------------- /working introduction/09 - g) Order of Evaluation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "In any expression containing multiple elements, it is necessary to have rules about the order in which the elements will be evaluated. One basic, widely used rule, which is also used by APL, is that an expression in parentheses must be evaluated before its value can be used in any expression that contains it. In fact, parentheses can be used to completely specify the order of evaluation, as in the following examples." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "(2×3)+(4×5)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "Note that the rule governing parentheses controls not only the order in which functions are executed, but also the order in which data elements are grouped into vectors." 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "(2 3) (4 5)" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "(¯5+(7 2)×13) 3" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "(((⍳3)×4)+7 1 8)-2" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "If parentheses were the only way to specify the order of evaluation, complex expressions would become unreadable tangles of parentheses within parentheses. To simplify writing and reading of code, other rules are needed. APL has one simple, primary rule for evaluation of expressions: Except as modified by parentheses, evaluation proceeds from right to left.\n", 58 | "\n", 59 | C 60 | "Put another way, each function’s right argument is the result of the entire expression to its right (up to an unmatched closing parenthesis) and its left argument -- if it has one -- is the single value to its left, which may be a parenthesized expression or a vector, but cannot be a function." 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "Progressively adding redundant pairs of parentheses which duplicate this order can make it easier to see how it works." 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "a←10\n", 77 | "b←13" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "The following four expressions are all equivalent" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": {}, 91 | "outputs": [], 92 | "source": [ 93 | "a+3×⍳b-6" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "a+3×⍳(b-6)" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "a+3×(⍳(b-6))" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "a+(3×(⍳(b-6)))" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "Note that the result of the above is quite different from either of these two expressions, which are different from each other." 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "(a+3)×⍳b-6" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "(a+3×⍳b)-6" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "You might think that this rule is somehow backwards, because we are used to reading and writing left-to-right, not right-to-left. But that would be a mistake. *Reading* left-to-right is *evaluation* right-to-left.\n", 153 | "\n", 154 | "E.g., \"the top half of the bottom quarter\" does not mean \"take the top half, and then take the bottom quarter of the result\"; it means \"take the bottom quarter, and then take the top half of that result\". In fact, it develops its meaning in four stages from right to left:\n", 155 | "\n", 156 | "1. Quarter: divide into quarters;\n", 157 | "2. Bottom: take the bottom of those;\n", 158 | "3. Half: divide what was taken into halves;\n", 159 | "4. Top: take the top of those.\n", 160 | "\n", 161 | "So right-to-left *evaluation* is not \"strange\". It's perfectly natural." 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "metadata": {}, 167 | "source": [ 168 | "APL does not recognise the function hierarchies of common mathematical notation, and with good reason. Mathematical notation determines its order by the kind of function, e.g. doing multiplication and division before addition and subtraction. But this is true only for a few kinds of functions, which are represented by special symbols. For named functions, it uses the same right-to-left rule as APL. E.g., `exp sin log x` is evaluated as `exp (sin (log (x)))`. Since APL has far more primitive functions represented by graphic symbols, any hierarchy covering them all would be both arbitrary and impossible to remember. Instead, APL gives *all* functions the same priority, both primitive symbols and named functions created by the programmer, and applies the same right-to-left evaluation rule to them all.\n", 169 | "\n", 170 | "Rules of syntax and evaluation in APL are few, fixed, and fundamental. One may need to consult documentation to know what a primitive function does, but not to know how to fit it in syntactically, nor to know in what order it will be executed." 171 | ] 172 | } 173 | ], 174 | "metadata": { 175 | "kernelspec": { 176 | "display_name": "Dyalog APL", 177 | "language": "apl", 178 | "name": "dyalog-kernel" 179 | }, 180 | "language_info": { 181 | "file_extension": ".apl", 182 | "mimetype": "text/apl", 183 | "name": "APL" 184 | }, 185 | "tryapl": { 186 | "category": "Introductory Course", 187 | "description": "What comes before what in an APL expression", 188 | "name": "Lesson 09: g) Order of Evaluation" 189 | } 190 | }, 191 | "nbformat": 4, 192 | "nbformat_minor": 2 193 | } 194 | -------------------------------------------------------------------------------- /working introduction/04 - d) Characters (Text).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "APL is not just for numbers!" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "EnglishAlphabet←'abcdefghijklmnopqrstuvwxyz'\n", 17 | "DanskAlfabet←'abcdefghijklmnopqrstuvwxyzæøå'" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "The English alphabet has 26 letters. The Danish alphabet has 29." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "EaLen←≢EnglishAlphabet\n", 34 | "DaLen←≢DanskAlfabet" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "The greater of the two lengths:" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "EaLen⌈DaLen" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "And the lesser:" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "EaLen⌊DaLen" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "Does the English alphabet have fewer letters than the Danish?" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "EaLenbp" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "Corresponding elements of each parameter:" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "↑(bp[ix])(br[ix])(bv[ix])" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "Total cost for each quantity:" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "costs←bv[ix]+br[ix]×qty-bp[ix]" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "Each quantity, its cost, and its average cost per item:" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "⍉↑qty costs ((⌊0.5+100×costs÷qty)÷100)" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "metadata": {}, 171 | "source": [ 172 | "We define the cost calculation in function form, using each of the above techniques for accessing parameters.\n", 173 | "\n", 174 | "The first function uses the global names of the parameters.", 175 | "\n" 176 | "The second function passes the parameters as a left argument." 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": null, 182 | "metadata": {}, 183 | "outputs": [], 184 | "source": [ 185 | "%define\n", 186 | "BracketCost_g←{\n", 187 | " ix←+/⍵∘.>bracketPoints\n", 188 | " bv←0,+\\(¯1↓bracketRates)ׯ2 -/ bracketPoints\n", 189 | " rest←⍵-bracketPoints[ix]\n", 190 | " bv[ix]+bracketRates[ix]×rest\n", 191 | "}" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "The result of a multi-line dynamic function is the result of the first executed line which doesn’t assign its result. That value is returned immediately as the result of the function, and any subsequent code will be ignored.." 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "Now use the same procedure to define the second function. \n", 206 | "This one takes the parameters as a left argument" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "metadata": {}, 213 | "outputs": [], 214 | "source": [ 215 | "%define\n", 216 | "BracketCost_a←{\n", 217 | " bp br←⍺\n", 218 | " ix←+/⍵∘.>bp\n", 219 | " bv←0,+\\(¯1↓br)ׯ2 -/ bp\n", 220 | " rest←⍵-bp[ix]\n", 221 | " bv[ix]+br[ix]×rest\n", 222 | "}" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "Now we verify that both functions give the same results as the piecewise computation:" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": null, 235 | "metadata": {}, 236 | "outputs": [], 237 | "source": [ 238 | "costs ≡ BracketCost_g qty" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": null, 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "costs ≡ (bracketPoints bracketRates) BracketCost_a qty" 248 | ] 249 | } 250 | ], 251 | "metadata": { 252 | "kernelspec": { 253 | "display_name": "Dyalog APL", 254 | "language": "apl", 255 | "name": "dyalog-kernel" 256 | }, 257 | "language_info": { 258 | "file_extension": ".apl", 259 | "mimetype": "text/apl", 260 | "name": "APL" 261 | }, 262 | "tryapl": { 263 | "category": "Introductory Course", 264 | "description": "Where to keep and how to pass around data", 265 | "name": "Lesson 15: m) Parameters — Global Variables vs Arguments" 266 | } 267 | }, 268 | "nbformat": 4, 269 | "nbformat_minor": 2 270 | } 271 | -------------------------------------------------------------------------------- /Random Numbers.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "The question mark `?` implements the \"roll\" function in APL.\n", 8 | "\n", 9 | "`?n` will return a number pseudo-randomly selected from the integers in `⍳` with each integer having an equal chance of being selected." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "List the first 6 integers" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "data": { 26 | "text/html": [ 27 | "1 2 3 4 5 6\n", 28 | "" 29 | ] 30 | }, 31 | "execution_count": 1, 32 | "metadata": {}, 33 | "output_type": "execute_result" 34 | } 35 | ], 36 | "source": [ 37 | "⍳6" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "Now generate one of them at random:" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 2, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "data": { 54 | "text/html": [ 55 | "4\n", 56 | "" 57 | ] 58 | }, 59 | "execution_count": 2, 60 | "metadata": {}, 61 | "output_type": "execute_result" 62 | } 63 | ], 64 | "source": [ 65 | "?6" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "Try again, it has a 1 in 6 chance of being the same:" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 3, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "data": { 82 | "text/html": [ 83 | "3\n", 84 | "" 85 | ] 86 | }, 87 | "execution_count": 3, 88 | "metadata": {}, 89 | "output_type": "execute_result" 90 | } 91 | ], 92 | "source": [ 93 | "?6" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "If you kept executing `?6`, it would be like rolling a 6-sided die over and over. But what if we have 5 dice?" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 4, 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "data": { 110 | "text/html": [ 111 | "4 2 1 4 5\n", 112 | "" 113 | ] 114 | }, 115 | "execution_count": 4, 116 | "metadata": {}, 117 | "output_type": "execute_result" 118 | } 119 | ], 120 | "source": [ 121 | "?6 6 6 6 6" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "APL functions can take arrays as arguments and return arrays as results.\n", 129 | "\n", 130 | "Here's another way of rolling 5 dice at once:" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 5, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "data": { 140 | "text/html": [ 141 | "3 2 2 2 2\n", 142 | "" 143 | ] 144 | }, 145 | "execution_count": 5, 146 | "metadata": {}, 147 | "output_type": "execute_result" 148 | } 149 | ], 150 | "source": [ 151 | "?5⍴6" 152 | ] 153 | }, 154 | { 155 | "cell_type": "markdown", 156 | "metadata": {}, 157 | "source": [ 158 | "Now let's look at some ideas about probability.\n", 159 | "\n", 160 | "The casino table game known as \"craps\" uses 2 6-sided dice that are added to give results in the range of 2-12. The table of all possible rolls looks like this:" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 6, 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "data": { 170 | "text/html": [ 171 | "┌───┬───┬───┬───┬───┬───┐\n", 172 | "│1 1│1 2│1 3│1 4│1 5│1 6│\n", 173 | "├───┼───┼───┼───┼───┼───┤\n", 174 | "│2 1│2 2│2 3│2 4│2 5│2 6│\n", 175 | "├───┼───┼───┼───┼───┼───┤\n", 176 | "│3 1│3 2│3 3│3 4│3 5│3 6│\n", 177 | "├───┼───┼───┼───┼───┼───┤\n", 178 | "│4 1│4 2│4 3│4 4│4 5│4 6│\n", 179 | "├───┼───┼───┼───┼───┼───┤\n", 180 | "│5 1│5 2│5 3│5 4│5 5│5 6│\n", 181 | "├───┼───┼───┼───┼───┼───┤\n", 182 | "│6 1│6 2│6 3│6 4│6 5│6 6│\n", 183 | "└───┴───┴───┴───┴───┴───┘\n", 184 | "" 185 | ] 186 | }, 187 | "execution_count": 6, 188 | "metadata": {}, 189 | "output_type": "execute_result" 190 | } 191 | ], 192 | "source": [ 193 | "⍳6 6" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": {}, 199 | "source": [ 200 | "And the totals are given by summing \"each\" roll, in this case using APL's \"each\" operator `¨`" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 7, 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "data": { 210 | "text/html": [ 211 | "2 3 4 5 6 7\n", 212 | "3 4 5 6 7 8\n", 213 | "4 5 6 7 8 9\n", 214 | "5 6 7 8 9 10\n", 215 | "6 7 8 9 10 11\n", 216 | "7 8 9 10 11 12\n", 217 | "" 218 | ] 219 | }, 220 | "execution_count": 7, 221 | "metadata": {}, 222 | "output_type": "execute_result" 223 | } 224 | ], 225 | "source": [ 226 | "+/¨⍳6 6" 227 | ] 228 | }, 229 | { 230 | "cell_type": "markdown", 231 | "metadata": {}, 232 | "source": [ 233 | "So first, let's create a function to compute the elements in the range of results." 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": 8, 239 | "metadata": {}, 240 | "outputs": [ 241 | { 242 | "data": { 243 | "text/html": [ 244 | "2 3 4 5 6 7 8 9 10 11 12\n", 245 | "" 246 | ] 247 | }, 248 | "execution_count": 8, 249 | "metadata": {}, 250 | "output_type": "execute_result" 251 | } 252 | ], 253 | "source": [ 254 | "range←{(¯1+⍴,⍵)↓⍳+/⍵}\n", 255 | "range 6 6" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 9, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "data": { 265 | "text/html": [ 266 | "┌──┬────┬────────────────────┐\n", 267 | "│2 │271 │⎕⎕⎕ │\n", 268 | "├──┼────┼────────────────────┤\n", 269 | "│3 │582 │⎕⎕⎕⎕⎕⎕⎕ │\n", 270 | "├──┼────┼────────────────────┤\n", 271 | "│4 │908 │⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ │\n", 272 | "├──┼────┼────────────────────┤\n", 273 | "│5 │1099│⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ │\n", 274 | "├──┼────┼────────────────────┤\n", 275 | "│6 │1387│⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ │\n", 276 | "├──┼────┼────────────────────┤\n", 277 | "│7 │1676│⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕│\n", 278 | "├──┼────┼────────────────────┤\n", 279 | "│8 │1368│⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ │\n", 280 | "├──┼────┼────────────────────┤\n", 281 | "│9 │1087│⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ │\n", 282 | "├──┼────┼────────────────────┤\n", 283 | "│10│748 │⎕⎕⎕⎕⎕⎕⎕⎕⎕ │\n", 284 | "├──┼────┼────────────────────┤\n", 285 | "│11│593 │⎕⎕⎕⎕⎕⎕⎕ │\n", 286 | "├──┼────┼────────────────────┤\n", 287 | "│12│281 │⎕⎕⎕ │\n", 288 | "└──┴────┴────────────────────┘\n", 289 | "" 290 | ] 291 | }, 292 | "execution_count": 9, 293 | "metadata": {}, 294 | "output_type": "execute_result" 295 | } 296 | ], 297 | "source": [ 298 | "graph←{⍉↑t n('⎕'⍴⍨¨⌊0.5+20×{⍵÷⌈/⍵}n←+/(t←∪,+/¨⍳⍵)∘.=+/¨?⍺⍴⊂⍵)}\n", 299 | "10000 graph 6 6" 300 | ] 301 | } 302 | ], 303 | "metadata": { 304 | "kernelspec": { 305 | "display_name": "Dyalog APL", 306 | "language": "apl", 307 | "name": "dyalog-kernel" 308 | }, 309 | "language_info": { 310 | "file_extension": ".apl", 311 | "mimetype": "text/apl", 312 | "name": "APL" 313 | }, 314 | "tryapl": { 315 | "category": "Closer Looks at Some Functions", 316 | "description": "Taking APL for a Roll", 317 | "name": "Random Numbers: ?" 318 | } 319 | }, 320 | "nbformat": 4, 321 | "nbformat_minor": 2 322 | } 323 | -------------------------------------------------------------------------------- /working introduction/01 - a) Names and Expressions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Type a single number, and execute:" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "5" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "12.436" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "Try a series of numbers. In APL, such a series is called a **vector**:" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "4 31.0 15.63 10" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "4 31.0 15.63 10" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "The result of an expression is its value:" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "14+9" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "14-9 " 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "Values can also be given names:" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "length←4\n", 92 | "width←2.5" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "Using the names is equivalent to using their values" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "length width" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "area←length×width" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "area" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "length×width" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "4×2.5" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "height←5.55\n", 154 | "volume←height×area" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": null, 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "volume" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "height×length×width" 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "Numbers and names can be used together:" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": null, 185 | "metadata": {}, 186 | "outputs": [], 187 | "source": [ 188 | "5.55×length×width" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": null, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "height 4 2.5" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "Vectors can also be given names:" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "metadata": {}, 211 | "outputs": [], 212 | "source": [ 213 | "length←8 7 6 5\n", 214 | "width←2 3 4 5\n", 215 | "dimensions←height length width" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": null, 221 | "metadata": {}, 222 | "outputs": [], 223 | "source": [ 224 | "dimensions" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": {}, 230 | "source": [ 231 | "Functions also apply to vectors" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "length×width" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "metadata": {}, 246 | "source": [ 247 | "Parentheses specify the order of evaluation for an expression" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "perimeter←2×(length+width)" 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": null, 262 | "metadata": {}, 263 | "outputs": [], 264 | "source": [ 265 | "perimeter" 266 | ] 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "metadata": {}, 271 | "source": [ 272 | "A yield of 12% for 3 years" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": null, 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "1.12×1.12×1.12" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": null, 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [ 290 | "1.12*3" 291 | ] 292 | }, 293 | { 294 | "cell_type": "markdown", 295 | "metadata": {}, 296 | "source": [ 297 | "Capital from multiple investments" 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": null, 303 | "metadata": {}, 304 | "outputs": [], 305 | "source": [ 306 | "c←20 80 120×(1.12*3)" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": null, 312 | "metadata": {}, 313 | "outputs": [], 314 | "source": [ 315 | "c" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "Rounded down to the nearest dollar (or euro, pound, etc):" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [ 331 | "⌊c" 332 | ] 333 | }, 334 | { 335 | "cell_type": "markdown", 336 | "metadata": {}, 337 | "source": [ 338 | "Rounded to the nearest dollar (etc.):" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": null, 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [ 347 | "⌊0.5+c" 348 | ] 349 | }, 350 | { 351 | "cell_type": "markdown", 352 | "metadata": {}, 353 | "source": [ 354 | "Rounded to the nearest cent:" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": null, 360 | "metadata": {}, 361 | "outputs": [], 362 | "source": [ 363 | "(⌊0.5+c×100)÷100" 364 | ] 365 | }, 366 | { 367 | "cell_type": "markdown", 368 | "metadata": {}, 369 | "source": [ 370 | "The purpose of any specific example is to provide a basis for discovering the idea of the general case. Thus the example `1.12*3` should suggest that any pair of numbers may be used with the power function denoted by the star." 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "metadata": {}, 376 | "source": [ 377 | "What are the meanings of `9*2`, `9*0.5` and `6*0.5`?\n", 378 | "\n", 379 | "Modify the expression below ..." 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 15, 385 | "metadata": {}, 386 | "outputs": [ 387 | { 388 | "data": { 389 | "text/html": [ 390 | "81\n", 391 | "" 392 | ] 393 | }, 394 | "execution_count": 15, 395 | "metadata": {}, 396 | "output_type": "execute_result" 397 | } 398 | ], 399 | "source": [ 400 | "9*2" 401 | ] 402 | }, 403 | { 404 | "cell_type": "markdown", 405 | "metadata": {}, 406 | "source": [ 407 | "What is the meaning of `⌈`, a new symbol, but one that is graphically similar to `⌊`? Many APL symbols are iconic, visual indications of their function. These names can be just as *meaningful* as English names like sort, reverse, and average." 408 | ] 409 | }, 410 | { 411 | "cell_type": "markdown", 412 | "metadata": {}, 413 | "source": [ 414 | "## Terminology\n", 415 | "\n", 416 | "Symbols such as `+` and `×` are **functions** which apply to **arguments** to produce **results**. Thus `8÷2` means that the divide function, `÷`, is applied to the left argument `8` and the right argument `2` to produce the result `4`, which is the quotient of `8` divided by `2`." 417 | ] 418 | } 419 | ], 420 | "metadata": { 421 | "kernelspec": { 422 | "display_name": "Dyalog APL", 423 | "language": "apl", 424 | "name": "dyalog-kernel" 425 | }, 426 | "language_info": { 427 | "file_extension": ".apl", 428 | "mimetype": "text/apl", 429 | "name": "APL" 430 | }, 431 | "tryapl": { 432 | "category": "Introductory Course", 433 | "description": "APL values and how to keep them", 434 | "name": "Lesson 01: a) Names and Expressions" 435 | } 436 | }, 437 | "nbformat": 4, 438 | "nbformat_minor": 2 439 | } 440 | -------------------------------------------------------------------------------- /working introduction/07 - f) More characters, Names, and Structure.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Let's have a look at dealing with text again." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "oil←10000+?7 6 12⍴100000" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "extra←' extra spaces'" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "In character vectors, spaces are considered part of the data, so multiple spaces are retained in the display." 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "extra" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "'extra' 'spaces'" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "But what happened here?" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "The result isn’t a single text vector, but a vector of text vectors. The boxed display indicates a difference in structure." 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "Be careful of the difference between text, which is enclosed in quotes, and names, which are not." 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "'extra' spaces" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": {}, 86 | "source": [ 87 | "Forgetting to enclose text in quotes can produce errors.\n", 88 | "\n", 89 | "Including errors that are still valid APL, and therefore give undesired results:" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "extra 'spaces'" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "Multiply nested structure is possible:" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "nummat←3 3⍴⍳9\n", 115 | "deep←((2 3) extra) nummat (⍳5)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "Any parenthesis pair with its enclosed expression has the value of the enclosed expression. Thus parentheses can be used to build structured data." 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "deep" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "A sequence of individual characters, like individual numbers or names, forms a vector." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [ 147 | "'a' 'b' 'c'" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | "But the same vector can be formed using only a single pair of quotes." 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": null, 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "'abc'" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "The two are identical:" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": null, 176 | "metadata": {}, 177 | "outputs": [], 178 | "source": [ 179 | "'abc'≡'a' 'b' 'c'" 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "metadata": {}, 185 | "source": [ 186 | "Here each pair of quotes forms a separate vector:" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": null, 192 | "metadata": {}, 193 | "outputs": [], 194 | "source": [ 195 | "'ab' 'bc' 'cd'" 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "metadata": {}, 201 | "source": [ 202 | "And the result is a vector of vectors." 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "The **rank** (number of dimensions) and **shape** (length along each dimension) of different arrays:" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "(≢⍴oil) (⍴oil)" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "(≢⍴nummat) (⍴nummat)" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": null, 233 | "metadata": {}, 234 | "outputs": [], 235 | "source": [ 236 | "(≢⍴extra) (⍴extra)" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": null, 242 | "metadata": {}, 243 | "outputs": [], 244 | "source": [ 245 | "(≢⍴'a') (⍴'a')" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": null, 251 | "metadata": {}, 252 | "outputs": [], 253 | "source": [ 254 | "(≢⍴3.2) (⍴3.2)" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": {}, 260 | "source": [ 261 | "Individual characters and numbers are also arrays, but arrays with no dimensions, and thus with no lengths in their shape vectors. Arrays which have no dimensions are known as **scalars**.\n", 262 | "\n", 263 | "The shape of a scalar is an **empty vector**. An empty vector has a length (of 0), but contains no elements, while a scalar contains one element, but has no length." 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "There are various ways to generate empty vectors. Here are some of the simplest:" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "Empty character vectors:" 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": null, 283 | "metadata": {}, 284 | "outputs": [], 285 | "source": [ 286 | "''" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": null, 292 | "metadata": {}, 293 | "outputs": [], 294 | "source": [ 295 | "0⍴'abc'" 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "metadata": {}, 301 | "source": [ 302 | "Empty numeric vectors:" 303 | ] 304 | }, 305 | { 306 | "cell_type": "code", 307 | "execution_count": null, 308 | "metadata": {}, 309 | "outputs": [], 310 | "source": [ 311 | "0⍴5" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": null, 317 | "metadata": {}, 318 | "outputs": [], 319 | "source": [ 320 | "⍬" 321 | ] 322 | }, 323 | { 324 | "cell_type": "markdown", 325 | "metadata": {}, 326 | "source": [ 327 | "An empty vector appended to another vector adds nothing:" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": null, 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [ 336 | "'abc'≡'','abc'" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": null, 342 | "metadata": {}, 343 | "outputs": [], 344 | "source": [ 345 | "'abc'≡'abc',''" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": null, 351 | "metadata": {}, 352 | "outputs": [], 353 | "source": [ 354 | "⍴⍬,3 17.2 ¯45" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "While the result of appending a scalar to any vector is a vector:" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "(≢⍴4 5 9,3) (⍴4 5 9,3)" 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "metadata": {}, 376 | "source": [ 377 | "Even when the initial vector is empty." 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "execution_count": null, 383 | "metadata": {}, 384 | "outputs": [], 385 | "source": [ 386 | "(≢⍴⍬,3) (⍴⍬.3)" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "But the simplest way to create a 1-element vector is by using **ravel**:" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": null, 399 | "metadata": {}, 400 | "outputs": [], 401 | "source": [ 402 | "⍴,3" 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "execution_count": null, 408 | "metadata": {}, 409 | "outputs": [], 410 | "source": [ 411 | "⍴,'c'" 412 | ] 413 | } 414 | ], 415 | "metadata": { 416 | "kernelspec": { 417 | "display_name": "Dyalog APL", 418 | "language": "apl", 419 | "name": "dyalog-kernel" 420 | }, 421 | "language_info": { 422 | "file_extension": ".apl", 423 | "mimetype": "text/apl", 424 | "name": "APL" 425 | }, 426 | "tryapl": { 427 | "category": "Introductory Course", 428 | "description": "Going deeper into arrays", 429 | "name": "Lesson 07: f) More Characters and Names and Structure" 430 | } 431 | }, 432 | "nbformat": 4, 433 | "nbformat_minor": 2 434 | } 435 | -------------------------------------------------------------------------------- /working introduction/11 - i) Numbers, Numeric Text, and Formatted Data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "C2N←{⊃(//⎕VFI ⍵)}\n", 10 | "C2N0←{⊃⌽⎕VFI ⍵}\n", 11 | "sales02←12 5⍴1835.2 1667.2 966.721 3378.24 2286.72 1649.9 1427.3 963.9 3103.38 2070.6 1772.8 1802.4 1159.68 3542.4 2208.96 1771.5 1695 1010.7 2809.35 2240.1 1944.8 1816.45 1155.66 3595.5 2380.68 1741.65 1933.75 1176.06 3571.02 2292.96 2057.4 2065.5 1199.34 3363.12 2432.16 2129.4 1814.4 1094.04 3664.44 2333.88 1816.2 1910.7 1109.16 3551.04 2458.08 2069.1 2075.4 1332.72 3866.94 2437.56 2019.6 2093.4 1268.46 3570.48 2423.52 2016 2120.4 1224.72 3465.18 2487.24\n", 12 | "months←12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec'\n", 13 | "items←' gas oil tires access other '\n", 14 | "Align←{(1+-⌈/≢¨,⍵)↑¨⍵}" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "Experiment with the two following sets of expressions to demonstrate that numeric text (digits, decimals, etc. enclosed within quotes) behaves differently from the numbers it represents:" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "n←123 456\n", 31 | "⍴n\n", 32 | "2×n\n", 33 | "n,n" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": null, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "c←'123 456'\n", 43 | "⍴c\n", 44 | "2×c\n", 45 | "c,c" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "The following examples illustrate the use of a primitive function which acts on numbers to produces character (text) representations of those numbers, as well as the defined functions `C2N` (which stands for \"character to number\") and `C2N0` (which stands for \"character to number with zero\") that convert character vectors to numbers." 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "na←C2N c\n", 62 | "⍴na\n", 63 | "2×na\n", 64 | "na,na" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "ca←⍕n\n", 74 | "⍴ca\n", 75 | "2×ca\n", 76 | "ca,ca" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "C2N c,c" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": null, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "C2N c,' ',c" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "What is the difference in what these two functions do?" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": null, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | "C2N c,' text ',c" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "C2N0 c,' text ',c" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "NOTE: The primitive function `⍎`, which looks like an inverse to `⍕`, can do character-to-number conversion, but it does much more than that, and its power can be dangerous. Its use for simple conversion is therefore not recommended, and instruction in its use is saved for a more advanced course." 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "Reports may be produced by catenating textual information with a character representation of the matrix of numeric data:" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "sales02 ⍝ A table of monthly sales for 2002." 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "msales←months,' ',⍕sales02\n", 152 | "msales" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "But there’s a problem: The default format omits trailing zeros in the decimal part, but we want them in a report of cash amounts." 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "There is also a solution: The format function can be given a left argument to override this default.\n", 167 | "\n", 168 | "The left argument of `2` specifies display of exactly 2 decimals." 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "msales←months,' ',2⍕sales02\n", 178 | "msales" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "Next we want to put headings on the columns" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": null, 191 | "metadata": {}, 192 | "outputs": [], 193 | "source": [ 194 | "report←items,[1]msales\n", 195 | "report" 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "metadata": {}, 201 | "source": [ 202 | "But now there’s another problem. The size of the numbers in real sales data can vary. The column width, counted as characters, varies with the number of digits, with the result that the column headings might not line up properly. Again, the format function provides a solution, allowing us to specify a column width in addition to the number of decimals." 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": null, 208 | "metadata": {}, 209 | "outputs": [], 210 | "source": [ 211 | "msales←months,' ',8 2⍕sales02" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": null, 217 | "metadata": {}, 218 | "outputs": [], 219 | "source": [ 220 | "report←items,[1]msales" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [ 229 | "report" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "metadata": {}, 235 | "source": [ 236 | "This is the traditional way to generate a report, and it’s useful, but it lacks flexibility. Nested arrays -- arrays with deeper structure -- can be helpful in that regard." 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": null, 242 | "metadata": {}, 243 | "outputs": [], 244 | "source": [ 245 | "Months←'Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec'\n", 246 | "Items←'Gas' 'Oil' 'Tires' 'Accessories' 'Other'" 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": null, 252 | "metadata": {}, 253 | "outputs": [], 254 | "source": [ 255 | "≢¨Items" 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "metadata": {}, 261 | "source": [ 262 | "These labels and headings are vector of vectors, with no added blanks.\n", 263 | "\n", 264 | "Here the **shape** function has been used with the **each** operator to show the shapes of the individual elements of `Items`, each of which is a separate text vector." 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "execution_count": null, 270 | "metadata": {}, 271 | "outputs": [], 272 | "source": [ 273 | "Report←(' ',Months),Items,[1] 2⍕¨sales02\n", 274 | "⍴Report" 275 | ] 276 | }, 277 | { 278 | "cell_type": "markdown", 279 | "metadata": {}, 280 | "source": [ 281 | "Is the added space necessary? Why?\n", 282 | "\n", 283 | "Explain the width of 6." 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "metadata": {}, 289 | "source": [ 290 | "Here each number has been formatted separately, so that its text representation becomes a single element in a single column of a matrix. Appending the headings -- also single elements -- to the top of this matrix insures that they will always line up with the columns of data, even if you use different item names." 291 | ] 292 | }, 293 | { 294 | "cell_type": "markdown", 295 | "metadata": {}, 296 | "source": [ 297 | "There are two things left to do:" 298 | ] 299 | }, 300 | { 301 | "cell_type": "markdown", 302 | "metadata": {}, 303 | "source": [ 304 | "`Align` right-aligns the formatted numbers." 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": {}, 311 | "outputs": [], 312 | "source": [ 313 | "Report←(' ',Months),Items,[1] Align 2⍕¨sales02\n", 314 | "⍴Report" 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": {}, 320 | "source": [ 321 | "Monadic `⍕` produces a simple (non-nested) text representation of *any* array." 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": null, 327 | "metadata": {}, 328 | "outputs": [], 329 | "source": [ 330 | "Report←⍕(' ',Months),Items,[1] Align 2⍕¨sales02\n", 331 | "⍴Report" 332 | ] 333 | }, 334 | { 335 | "cell_type": "code", 336 | "execution_count": null, 337 | "metadata": {}, 338 | "outputs": [], 339 | "source": [ 340 | "Report" 341 | ] 342 | } 343 | ], 344 | "metadata": { 345 | "kernelspec": { 346 | "display_name": "Dyalog APL", 347 | "language": "apl", 348 | "name": "dyalog-kernel" 349 | }, 350 | "language_info": { 351 | "file_extension": ".apl", 352 | "mimetype": "text/apl", 353 | "name": "APL" 354 | }, 355 | "tryapl": { 356 | "category": "Introductory Course", 357 | "description": "How to treat numbers as text", 358 | "name": "Lesson 11: i) Numbers as Text and Formatted Data" 359 | } 360 | }, 361 | "nbformat": 4, 362 | "nbformat_minor": 2 363 | } 364 | -------------------------------------------------------------------------------- /Lookup Without Replacement.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Consider two vectors, e.g. **L**: `'abacba'` and **R**: `'baabaac'`.\n", 8 | "By now, you should know about dyadic `⍳`: " 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "data": { 18 | "text/html": [ 19 | "2 1 1 2 1 1 4\n", 20 | "" 21 | ] 22 | }, 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "output_type": "execute_result" 26 | } 27 | ], 28 | "source": [ 29 | "L←'abacba'\n", 30 | "R←'baabaac'\n", 31 | "L⍳R" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "That finds first location in **L** of each element in **R**.\n", 39 | "\n", 40 | "However, what if we wanted the first b in **R** to \"consume\" the first b in **L** so that the second b in **R** would have to contend with the index of the second b in **L**?\n", 41 | "\n", 42 | "That is, we want some function which gives `2 1 3 5 6 7 4`. You could call it \"iota without replacement\". As, in a sense, the iota *progresses* through **L** as it finds element from **R**, it is also known in APL circles as \"progressive dyadic iota\"." 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 2, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "data": { 52 | "text/html": [ 53 | "2 1 3 5 6 7 4\n", 54 | "" 55 | ] 56 | }, 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "output_type": "execute_result" 60 | } 61 | ], 62 | "source": [ 63 | "'a1' 'b1' 'a2' 'c1' 'b2' 'a3' ⍳ 'b1' 'a1' 'a2' 'b2' 'a3' 'a4' 'c1'" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "So, because we numbered the as (which otherwise all match each other) and the bs, the right pairs get matched up. \n", 71 | "\n", 72 | "While `⍋` gives us the indices that will sort, `⍋⍋` gives us the positions that each element will occupy in the sorted result." 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 3, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "data": { 82 | "text/html": [ 83 | "a b a c b a\n", 84 | "1 2 1 4 2 1\n", 85 | "1 4 2 6 5 3\n", 86 | "" 87 | ] 88 | }, 89 | "execution_count": 3, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "↑L (L⍳L) (⍋⍋L⍳L)" 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "The first line is the data and the second is the indices of the first occurrences (i.e. all identical items will get the same index). The third line is the position that each will occupy when sorted. That means that identical elements get consecutive positions.\n", 103 | "\n", 104 | "E.g. you can see that the first b gets 4 (because there are 3 as) and the second gets 5." 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "We can label both vectors in this way:" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 4, 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "data": { 121 | "text/html": [ 122 | "1 2 2 1 2 2 7\n", 123 | "" 124 | ] 125 | }, 126 | "execution_count": 4, 127 | "metadata": {}, 128 | "output_type": "execute_result" 129 | } 130 | ], 131 | "source": [ 132 | "(L⍳L)⍳(R⍳R)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "This almost solves the problem (although it might not look like it), but this labelling depends on both the order and the frequency of the elements in a vector. However, we need both vectors to be labelled in the same way, i.e the first `a` in each vector will get same label, and the second `b` in each will also get matching labels." 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "Since we're going to look up elements of **R** in **L** anyway, we can use indices into **L** (that is `L⍳R`) instead of the lookup of **R** into itself (`R⍳R`) This ensures that elements of **R** are labelled with \"L's labelling system\". " 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 5, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/html": [ 157 | "a b a c b a\n", 158 | "1 2 1 4 2 1\n", 159 | "1 4 2 6 5 3\n", 160 | "" 161 | ] 162 | }, 163 | "execution_count": 5, 164 | "metadata": {}, 165 | "output_type": "execute_result" 166 | } 167 | ], 168 | "source": [ 169 | "↑L (L⍳L) (⍋⍋L⍳L)" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 6, 175 | "metadata": { 176 | "scrolled": true 177 | }, 178 | "outputs": [ 179 | { 180 | "data": { 181 | "text/html": [ 182 | "b a a b a a c\n", 183 | "2 1 1 2 1 1 4\n", 184 | "5 1 2 6 3 4 7\n", 185 | "" 186 | ] 187 | }, 188 | "execution_count": 6, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "↑R (L⍳R) (⍋⍋L⍳R)" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "The only problem that remains is that **L** and **R** have their elements with different frequencies. The first b of **R** is labelled 5, whereas the first b of **L** is labelled 4. This is because **L** has one less a." 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": {}, 207 | "source": [ 208 | "To solve this we need the second argument of each `⍳` to have the same number of each element when labelling both **L** and **R**. The easiest way to do this is with `L⍪R` and `R⍪L`. `⍪` is used instead of `,` so that the method can be used for higher rank arrays." 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 7, 214 | "metadata": {}, 215 | "outputs": [ 216 | { 217 | "data": { 218 | "text/html": [ 219 | "1 8 2 12 9 3 10 4 5 11 6 7 13\n", 220 | "" 221 | ] 222 | }, 223 | "execution_count": 7, 224 | "metadata": {}, 225 | "output_type": "execute_result" 226 | } 227 | ], 228 | "source": [ 229 | "⍋⍋L⍳L,R" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 8, 235 | "metadata": {}, 236 | "outputs": [ 237 | { 238 | "data": { 239 | "text/html": [ 240 | "8 1 2 9 3 4 12 5 10 6 13 11 7\n", 241 | "" 242 | ] 243 | }, 244 | "execution_count": 8, 245 | "metadata": {}, 246 | "output_type": "execute_result" 247 | } 248 | ], 249 | "source": [ 250 | "⍋⍋L⍳R,L" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "So, now we are working in precisely the same labelling scheme for both **L** and **R**, we just need use `↑` to remove the unneeded elements." 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 9, 263 | "metadata": {}, 264 | "outputs": [ 265 | { 266 | "data": { 267 | "text/html": [ 268 | "1 8 2 12 9 3\n", 269 | "" 270 | ] 271 | }, 272 | "execution_count": 9, 273 | "metadata": {}, 274 | "output_type": "execute_result" 275 | } 276 | ], 277 | "source": [ 278 | "(≢L)↑⍋⍋L⍳L⍪R" 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": 10, 284 | "metadata": {}, 285 | "outputs": [ 286 | { 287 | "data": { 288 | "text/html": [ 289 | "8 1 2 9 3 4 12\n", 290 | "" 291 | ] 292 | }, 293 | "execution_count": 10, 294 | "metadata": {}, 295 | "output_type": "execute_result" 296 | } 297 | ], 298 | "source": [ 299 | "(≢R)↑⍋⍋L⍳R⍪L" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 11, 305 | "metadata": {}, 306 | "outputs": [ 307 | { 308 | "data": { 309 | "text/html": [ 310 | "2 1 3 5 6 7 4\n", 311 | "" 312 | ] 313 | }, 314 | "execution_count": 11, 315 | "metadata": {}, 316 | "output_type": "execute_result" 317 | } 318 | ], 319 | "source": [ 320 | "((≢L)↑⍋⍋L⍳L⍪R)⍳((≢R)↑⍋⍋L⍳R⍪L)" 321 | ] 322 | }, 323 | { 324 | "cell_type": "markdown", 325 | "metadata": {}, 326 | "source": [ 327 | "Now, we can define this function:" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": 12, 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [ 336 | "f←{((≢⍺)↑⍋⍋⍺⍳⍺⍪⍵)⍳((≢⍵)↑⍋⍋⍺⍳⍵⍪⍺)}" 337 | ] 338 | }, 339 | { 340 | "cell_type": "markdown", 341 | "metadata": {}, 342 | "source": [ 343 | "A use case of this function is in a first-come, first-served queue. For example you might have First Class, Premium, Business, and Economy seats on a plane. This function will allocate seats based on which class was ordered." 344 | ] 345 | }, 346 | { 347 | "cell_type": "markdown", 348 | "metadata": {}, 349 | "source": [ 350 | "Lets say we have a plane: `'11bbbpeepee'` where 1 is first class, p is premium, b is business, and e is economy. And we have a bunch of customers coming to buy seats: `'bbepbeppe1ee'`." 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 13, 356 | "metadata": {}, 357 | "outputs": [ 358 | { 359 | "data": { 360 | "text/html": [ 361 | "3 4 7 6 5 8 9 12 10 1 11 12\n", 362 | "" 363 | ] 364 | }, 365 | "execution_count": 13, 366 | "metadata": {}, 367 | "output_type": "execute_result" 368 | } 369 | ], 370 | "source": [ 371 | "'11bbbpeepee' f 'bbepbeppe1ee'" 372 | ] 373 | }, 374 | { 375 | "cell_type": "markdown", 376 | "metadata": {}, 377 | "source": [ 378 | "Person number 1 gets seat 3, person number 3 gets seat 7, and so on. People 8 and 12 however cannot get a seat, because all of the seats of their type have been allocated already. This is indicated by the result `12` which is out of the bounds of plane (length-11)." 379 | ] 380 | } 381 | ], 382 | "metadata": { 383 | "kernelspec": { 384 | "display_name": "Dyalog APL", 385 | "language": "apl", 386 | "name": "dyalog-kernel" 387 | }, 388 | "language_info": { 389 | "file_extension": ".apl", 390 | "mimetype": "text/apl", 391 | "name": "APL" 392 | }, 393 | "tryapl": { 394 | "category": "Interesting Explorations", 395 | "description": "Lookup Without Replacement (a.k.a. Dynamic Progressive Iota)", 396 | "name": "Lookup Without Replacement" 397 | } 398 | }, 399 | "nbformat": 4, 400 | "nbformat_minor": 2 401 | } 402 | -------------------------------------------------------------------------------- /Grading and Sorting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "There is no sort primitive in APL, although sorting can be easily achieved with the use of `⍋` (grade up) or `⍒` (grade down).\n", 8 | "\n", 9 | "`⍋` takes an array and returns the indices of the major cells in ascending order. From the least major cell to the greatest major cell. It is easiest to understand with an example:" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "data": { 19 | "text/html": [ 20 | "2 4 1 3 5\n", 21 | "" 22 | ] 23 | }, 24 | "execution_count": 1, 25 | "metadata": {}, 26 | "output_type": "execute_result" 27 | } 28 | ], 29 | "source": [ 30 | "V←3 1 4 1 5\n", 31 | "⍋V" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "This means that the smallest element is the second one (`1`), then the forth (also `1`), then the first (`3`), etc.\n", 39 | "\n", 40 | "So, we can use this to sort the array:" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 2, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "data": { 50 | "text/html": [ 51 | "1 1 3 4 5\n", 52 | "" 53 | ] 54 | }, 55 | "execution_count": 2, 56 | "metadata": {}, 57 | "output_type": "execute_result" 58 | } 59 | ], 60 | "source": [ 61 | "V[⍋V]" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "It works on arrays of any rank greater than 0:" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 3, 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "data": { 78 | "text/html": [ 79 | "2 7\n", 80 | "1 8\n", 81 | "2 8\n", 82 | "" 83 | ] 84 | }, 85 | "execution_count": 3, 86 | "metadata": {}, 87 | "output_type": "execute_result" 88 | } 89 | ], 90 | "source": [ 91 | "M←3 2⍴2 7 1 8 2 8\n", 92 | "M" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 4, 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "data": { 102 | "text/html": [ 103 | "2 1 3\n", 104 | "" 105 | ] 106 | }, 107 | "execution_count": 4, 108 | "metadata": {}, 109 | "output_type": "execute_result" 110 | } 111 | ], 112 | "source": [ 113 | "⍋M" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": {}, 119 | "source": [ 120 | "So the first is row 2 (`1 8`) then row 1 (`2 7`) then row 3 (`2 8`). This is a lexicographic ordering - The cells are compared item by item, until there is a difference.\n", 121 | "\n", 122 | "Characters are compared using their Unicode codepoints:" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 5, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "data": { 132 | "text/html": [ 133 | "He\n", 134 | "ll\n", 135 | "oW\n", 136 | "or\n", 137 | "ld\n", 138 | "" 139 | ] 140 | }, 141 | "execution_count": 5, 142 | "metadata": {}, 143 | "output_type": "execute_result" 144 | } 145 | ], 146 | "source": [ 147 | "Greeting←5 2⍴'HelloWorld'\n", 148 | "Greeting" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 6, 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "data": { 158 | "text/html": [ 159 | "1 5 2 3 4\n", 160 | "" 161 | ] 162 | }, 163 | "execution_count": 6, 164 | "metadata": {}, 165 | "output_type": "execute_result" 166 | } 167 | ], 168 | "source": [ 169 | "⍋Greeting" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 7, 175 | "metadata": {}, 176 | "outputs": [ 177 | { 178 | "data": { 179 | "text/html": [ 180 | "He\n", 181 | "ld\n", 182 | "ll\n", 183 | "oW\n", 184 | "or\n", 185 | "" 186 | ] 187 | }, 188 | "execution_count": 7, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "Greeting[⍋Greeting;]" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "To sort an array of any rank, one can define a function:" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 8, 207 | "metadata": {}, 208 | "outputs": [ 209 | { 210 | "data": { 211 | "text/html": [ 212 | "1 1 1 1 4 5 6 7\n", 213 | "" 214 | ] 215 | }, 216 | "execution_count": 8, 217 | "metadata": {}, 218 | "output_type": "execute_result" 219 | } 220 | ], 221 | "source": [ 222 | "sortUp←{(⊂⍋⍵)⌷⍵}\n", 223 | "sortUp 1 4 1 5 1 6 1 7" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "`⍒` is grade down. It behaves in the same way as `⍋` but grade in descending order." 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 9, 236 | "metadata": {}, 237 | "outputs": [ 238 | { 239 | "data": { 240 | "text/html": [ 241 | "23 19 17 13 11 7 5 3 2\n", 242 | "" 243 | ] 244 | }, 245 | "execution_count": 9, 246 | "metadata": {}, 247 | "output_type": "execute_result" 248 | } 249 | ], 250 | "source": [ 251 | "sortDown←{(⊂⍒⍵)⌷⍵}\n", 252 | "sortDown 11 5 3 23 7 17 2 13 19" 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": {}, 258 | "source": [ 259 | "As of version 17, you can grade **any** array (as long as it doesn't contain refs). The rules for this are complicated and can be found [on the Dyalog web help for Total Array Ordering](http://help.dyalog.com/latest/#RelNotes17.0/Total%20Array%20Ordering.htm)." 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": 10, 265 | "metadata": {}, 266 | "outputs": [ 267 | { 268 | "data": { 269 | "text/html": [ 270 | "┌───┬─────┬──────┬─────┬────┐\n", 271 | "│car│cards│carpet│train│tram│\n", 272 | "└───┴─────┴──────┴─────┴────┘\n", 273 | "" 274 | ] 275 | }, 276 | "execution_count": 10, 277 | "metadata": {}, 278 | "output_type": "execute_result" 279 | } 280 | ], 281 | "source": [ 282 | "sortUp 'carpet' 'car' 'cards' 'train' 'tram'" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 11, 288 | "metadata": {}, 289 | "outputs": [ 290 | { 291 | "data": { 292 | "text/html": [ 293 | "┌───┬───────┬───────┬────┬───┬──┐\n", 294 | "│2 5│2 5 1 3│2 5 1 3│2513│abc│xx│\n", 295 | "│1 3│ │ │ │ │xx│\n", 296 | "│ │ │ │ │ │ │\n", 297 | "│ │ │ │ │ │xx│\n", 298 | "│ │ │ │ │ │xx│\n", 299 | "│ │ │ │ │ │ │\n", 300 | "│ │ │ │ │ │xx│\n", 301 | "│ │ │ │ │ │xx│\n", 302 | "└───┴───────┴───────┴────┴───┴──┘\n", 303 | "" 304 | ] 305 | }, 306 | "execution_count": 11, 307 | "metadata": {}, 308 | "output_type": "execute_result" 309 | } 310 | ], 311 | "source": [ 312 | "⊢ (2 2⍴2 5 1 3) (2 5 1 3) (1 4⍴2 5 1 3) '2513' 'abc' (3 2 2⍴'x')" 313 | ] 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "metadata": {}, 318 | "source": [ 319 | "Grading can be used for more than just sorting. To get the index of the maximum value in an array, you use `⊃⍒`:" 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": 12, 325 | "metadata": {}, 326 | "outputs": [ 327 | { 328 | "data": { 329 | "text/html": [ 330 | "5\n", 331 | "" 332 | ] 333 | }, 334 | "execution_count": 12, 335 | "metadata": {}, 336 | "output_type": "execute_result" 337 | } 338 | ], 339 | "source": [ 340 | "⊃⍒6 3 2 1 88 32 6 10.7" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "`{⍋⍋⍵}` is another useful function. While `⍋⍵` gives the indices that sort `⍵`, `⍋⍋⍵` gives the positions that each element of `⍵` would occupy after sorting. You can also think of `⍋` as inverting the permutation you give it." 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 13, 353 | "metadata": {}, 354 | "outputs": [ 355 | { 356 | "data": { 357 | "text/html": [ 358 | "3 5 6 1 2 4\n", 359 | "" 360 | ] 361 | }, 362 | "execution_count": 13, 363 | "metadata": {}, 364 | "output_type": "execute_result" 365 | } 366 | ], 367 | "source": [ 368 | "A←4 6 8 1 2 4\n", 369 | "⍋⍋A" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "The first element (`4`) is the third smallest element, the second element (`6`) is the fifth smallest, and so on. It is fairly common to use `⍋⍋` to *normalise* a vector, `V`, to a permutation of `⍳≢V` which has the same ordering as `V`." 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "## Dyadic Grade\n", 384 | "\n", 385 | "Grade can also be used dyadically for character arrays. `{⍺⍋⍵}` will grade `⍵` according to the alphabet `⍺`." 386 | ] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "execution_count": 14, 391 | "metadata": {}, 392 | "outputs": [ 393 | { 394 | "data": { 395 | "text/html": [ 396 | "2 5 7 10 1 3 4 9 8 6\n", 397 | "" 398 | ] 399 | }, 400 | "execution_count": 14, 401 | "metadata": {}, 402 | "output_type": "execute_result" 403 | } 404 | ], 405 | "source": [ 406 | "'aeioubcdfghjklmnpqrstvwxyz'⍋'helloworld'" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 15, 412 | "metadata": {}, 413 | "outputs": [ 414 | { 415 | "data": { 416 | "text/html": [ 417 | "eoodhlllrw\n", 418 | "" 419 | ] 420 | }, 421 | "execution_count": 15, 422 | "metadata": {}, 423 | "output_type": "execute_result" 424 | } 425 | ], 426 | "source": [ 427 | "{⍵['aeioubcdfghjklmnpqrstvwxyz'⍋⍵]}'helloworld'" 428 | ] 429 | }, 430 | { 431 | "cell_type": "markdown", 432 | "metadata": {}, 433 | "source": [ 434 | "There we sorted the vowels before the consonants. If characters are missing from the alphabet, they will be considered after the alphabet, and equivalent:" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": 16, 440 | "metadata": {}, 441 | "outputs": [ 442 | { 443 | "data": { 444 | "text/html": [ 445 | "2 1 3 4\n", 446 | "" 447 | ] 448 | }, 449 | "execution_count": 16, 450 | "metadata": {}, 451 | "output_type": "execute_result" 452 | } 453 | ], 454 | "source": [ 455 | "'abcdefgh'⍋'hawl'" 456 | ] 457 | } 458 | ], 459 | "metadata": { 460 | "kernelspec": { 461 | "display_name": "Dyalog APL", 462 | "language": "apl", 463 | "name": "dyalog-kernel" 464 | }, 465 | "language_info": { 466 | "file_extension": ".apl", 467 | "mimetype": "text/apl", 468 | "name": "APL" 469 | }, 470 | "tryapl": { 471 | "category": "Closer Looks at Some Functions", 472 | "description": "Grading and sorting with Grade Up and Grade Down", 473 | "name": "Grading and Sorting: ⍋ ⍒" 474 | } 475 | }, 476 | "nbformat": 4, 477 | "nbformat_minor": 2 478 | } 479 | -------------------------------------------------------------------------------- /Reduce and Scan.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "An operator takes 1 or 2 operands (which are usually functions) as arguments, and derives a function which itself can either be monadic or dyadic." 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "`/` (reduce) is a monadic operator which derives an ambivalent function. ambivalent meaning that it can be used both monadically and dyadically. It is called reduce because it always *reduces* the rank of its argument by 1.\n", 15 | "\n", 16 | "Reduction on a vector is straightforward; `F/a b c d e...` is equivalent to `⊂a F b F c F d F e...`. The result of a reduction will have the shape of the argument excluding the last axis." 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "data": { 26 | "text/html": [ 27 | "14\n", 28 | "" 29 | ] 30 | }, 31 | "execution_count": 1, 32 | "metadata": {}, 33 | "output_type": "execute_result" 34 | } 35 | ], 36 | "source": [ 37 | "+/3 1 4 1 5" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 2, 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "data": { 47 | "text/html": [ 48 | "14\n", 49 | "" 50 | ] 51 | }, 52 | "execution_count": 2, 53 | "metadata": {}, 54 | "output_type": "execute_result" 55 | } 56 | ], 57 | "source": [ 58 | "3 + 1 + 4 + 1 + 5" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 3, 64 | "metadata": {}, 65 | "outputs": [ 66 | { 67 | "data": { 68 | "text/html": [ 69 | "┌─────────┐\n", 70 | "│28 80 162│\n", 71 | "└─────────┘\n", 72 | "" 73 | ] 74 | }, 75 | "execution_count": 3, 76 | "metadata": {}, 77 | "output_type": "execute_result" 78 | } 79 | ], 80 | "source": [ 81 | "×/(1 2 3)(4 5 6)(7 8 9) ⍝ The result is enclosed, because the rank must be 0" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "Since functions in APL are right-associative, this has an effect on reduce. For example `-/` is alternating sum." 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 4, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "data": { 98 | "text/html": [ 99 | "¯2\n", 100 | "" 101 | ] 102 | }, 103 | "execution_count": 4, 104 | "metadata": {}, 105 | "output_type": "execute_result" 106 | } 107 | ], 108 | "source": [ 109 | "-/1 2 3 4" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 5, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "text/html": [ 120 | "¯2\n", 121 | "" 122 | ] 123 | }, 124 | "execution_count": 5, 125 | "metadata": {}, 126 | "output_type": "execute_result" 127 | } 128 | ], 129 | "source": [ 130 | "1-2-3-4" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "For higher rank arrays reduce will reduce along the last axis." 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 6, 143 | "metadata": {}, 144 | "outputs": [ 145 | { 146 | "data": { 147 | "text/html": [ 148 | "1 2 3 4\n", 149 | "5 6 7 8\n", 150 | "9 10 11 12\n", 151 | "" 152 | ] 153 | }, 154 | "execution_count": 6, 155 | "metadata": {}, 156 | "output_type": "execute_result" 157 | } 158 | ], 159 | "source": [ 160 | "3 4⍴⍳12" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 7, 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "data": { 170 | "text/html": [ 171 | "10 26 42\n", 172 | "" 173 | ] 174 | }, 175 | "execution_count": 7, 176 | "metadata": {}, 177 | "output_type": "execute_result" 178 | } 179 | ], 180 | "source": [ 181 | "+/3 4⍴⍳12" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "The twin of `/`, `⌿` reduces along the first axis, i.e the columns of a matrix." 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 8, 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "data": { 198 | "text/html": [ 199 | "15 18 21 24\n", 200 | "" 201 | ] 202 | }, 203 | "execution_count": 8, 204 | "metadata": {}, 205 | "output_type": "execute_result" 206 | } 207 | ], 208 | "source": [ 209 | "+⌿3 4⍴⍳12" 210 | ] 211 | }, 212 | { 213 | "cell_type": "markdown", 214 | "metadata": {}, 215 | "source": [ 216 | "If you need to reduce across some other axis, like the second in a rank-3 array, you can use `f/[axis]`. `f/[1]` is the same as `f⌿`." 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 9, 222 | "metadata": {}, 223 | "outputs": [ 224 | { 225 | "data": { 226 | "text/html": [ 227 | " 1 2 3 4\n", 228 | " 5 6 7 8\n", 229 | " 9 10 11 12\n", 230 | " \n", 231 | "13 14 15 16\n", 232 | "17 18 19 20\n", 233 | "21 22 23 24\n", 234 | "" 235 | ] 236 | }, 237 | "execution_count": 9, 238 | "metadata": {}, 239 | "output_type": "execute_result" 240 | } 241 | ], 242 | "source": [ 243 | "2 3 4⍴⍳24" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 10, 249 | "metadata": {}, 250 | "outputs": [ 251 | { 252 | "data": { 253 | "text/html": [ 254 | "┌───────────┬───────────┬────────┐\n", 255 | "│14 16 18 20│15 18 21 24│10 26 42│\n", 256 | "│22 24 26 28│51 54 57 60│58 74 90│\n", 257 | "│30 32 34 36│ │ │\n", 258 | "└───────────┴───────────┴────────┘\n", 259 | "" 260 | ] 261 | }, 262 | "execution_count": 10, 263 | "metadata": {}, 264 | "output_type": "execute_result" 265 | } 266 | ], 267 | "source": [ 268 | "(+⌿2 3 4⍴⍳24)(+/[2]2 3 4⍴⍳24)(+/2 3 4⍴⍳24)" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "As a dyadic function, `L f/ R` is a windowed reduction, i.e the `f`-reduction of each sliding window of size L in R." 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 11, 281 | "metadata": {}, 282 | "outputs": [ 283 | { 284 | "data": { 285 | "text/html": [ 286 | "4 5 5 6\n", 287 | "" 288 | ] 289 | }, 290 | "execution_count": 11, 291 | "metadata": {}, 292 | "output_type": "execute_result" 293 | } 294 | ], 295 | "source": [ 296 | "2 +/3 1 4 1 5" 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": 12, 302 | "metadata": {}, 303 | "outputs": [ 304 | { 305 | "data": { 306 | "text/html": [ 307 | "8 6 10\n", 308 | "" 309 | ] 310 | }, 311 | "execution_count": 12, 312 | "metadata": {}, 313 | "output_type": "execute_result" 314 | } 315 | ], 316 | "source": [ 317 | "3 +/ 3 1 4 1 5" 318 | ] 319 | }, 320 | { 321 | "cell_type": "markdown", 322 | "metadata": {}, 323 | "source": [ 324 | "Windowed reduction does not change the rank." 325 | ] 326 | }, 327 | { 328 | "cell_type": "code", 329 | "execution_count": 13, 330 | "metadata": {}, 331 | "outputs": [ 332 | { 333 | "data": { 334 | "text/html": [ 335 | " 3 5 7\n", 336 | "11 13 15\n", 337 | "19 21 23\n", 338 | "" 339 | ] 340 | }, 341 | "execution_count": 13, 342 | "metadata": {}, 343 | "output_type": "execute_result" 344 | } 345 | ], 346 | "source": [ 347 | "2 +/ 3 4⍴⍳12" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 14, 353 | "metadata": {}, 354 | "outputs": [ 355 | { 356 | "data": { 357 | "text/html": [ 358 | " 6 8 10 12\n", 359 | "14 16 18 20\n", 360 | "" 361 | ] 362 | }, 363 | "execution_count": 14, 364 | "metadata": {}, 365 | "output_type": "execute_result" 366 | } 367 | ], 368 | "source": [ 369 | "2 +⌿ 3 4⍴⍳12" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "If the left argument is negative, the windows are reversed." 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": 15, 382 | "metadata": {}, 383 | "outputs": [ 384 | { 385 | "data": { 386 | "text/html": [ 387 | "1 2 3 4 5\n", 388 | "" 389 | ] 390 | }, 391 | "execution_count": 15, 392 | "metadata": {}, 393 | "output_type": "execute_result" 394 | } 395 | ], 396 | "source": [ 397 | "¯2 -/ 0 1 3 6 10 15" 398 | ] 399 | }, 400 | { 401 | "cell_type": "markdown", 402 | "metadata": {}, 403 | "source": [ 404 | "Common uses of `/` are for sum with `+`, product with `×`, all with `∧`, and any with `∨`." 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "metadata": {}, 410 | "source": [ 411 | "`\\` (scan) is a similar monadic operator. It reduces each prefix of the last axis. For a vector this means that `f\\a b c d...` is `(f/a) (f/a b) (f/a b c) (f/a b c d) ...`\n", 412 | "\n", 413 | "A common use is for cumulative sum:" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 16, 419 | "metadata": {}, 420 | "outputs": [ 421 | { 422 | "data": { 423 | "text/html": [ 424 | "2 5 10 17 28\n", 425 | "" 426 | ] 427 | }, 428 | "execution_count": 16, 429 | "metadata": {}, 430 | "output_type": "execute_result" 431 | } 432 | ], 433 | "source": [ 434 | "+\\2 3 5 7 11" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": 17, 440 | "metadata": {}, 441 | "outputs": [ 442 | { 443 | "data": { 444 | "text/html": [ 445 | "1 3 6 10\n", 446 | "5 11 18 26\n", 447 | "9 19 30 42\n", 448 | "" 449 | ] 450 | }, 451 | "execution_count": 17, 452 | "metadata": {}, 453 | "output_type": "execute_result" 454 | } 455 | ], 456 | "source": [ 457 | "+\\3 4⍴⍳12" 458 | ] 459 | }, 460 | { 461 | "cell_type": "markdown", 462 | "metadata": {}, 463 | "source": [ 464 | "Similarly `\\` also has a twin `⍀` who behaves as you might expect. Scan on first axis." 465 | ] 466 | }, 467 | { 468 | "cell_type": "code", 469 | "execution_count": 18, 470 | "metadata": {}, 471 | "outputs": [ 472 | { 473 | "data": { 474 | "text/html": [ 475 | " 1 2 3 4\n", 476 | " 6 8 10 12\n", 477 | "15 18 21 24\n", 478 | "" 479 | ] 480 | }, 481 | "execution_count": 18, 482 | "metadata": {}, 483 | "output_type": "execute_result" 484 | } 485 | ], 486 | "source": [ 487 | "+⍀3 4⍴⍳12" 488 | ] 489 | } 490 | ], 491 | "metadata": { 492 | "kernelspec": { 493 | "display_name": "Dyalog APL", 494 | "language": "apl", 495 | "name": "dyalog-kernel" 496 | }, 497 | "language_info": { 498 | "file_extension": ".apl", 499 | "mimetype": "text/apl", 500 | "name": "APL" 501 | }, 502 | "tryapl": { 503 | "category": "Closer Looks at Some Operators", 504 | "description": "Combining data, even cumulatively.", 505 | "name": "Reduce and Scan: / \\" 506 | } 507 | }, 508 | "nbformat": 4, 509 | "nbformat_minor": 2 510 | } 511 | -------------------------------------------------------------------------------- /working introduction/14 - l) Reading APL Expressions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "How do you decipher a complex APL formula?" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "countries←↑'Saudi Arabia' 'Canada' 'Nigeria' 'Venezuela' 'Mexico' 'Other'\n", 17 | "oil←2 1 3⍉↑(1000×35 25 25 40 30 50)+?(⊂7 12)⍴¨1000×35 30 10 12 29 53" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "To read a simple but unfamiliar expression such as `a∘.+b` (i.e., to understand what it does), use it with a variety of arguments, and try to construct a rule that describes how the results are constructed from the arguments." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "a←2 3 4\n", 34 | "b←4 3 2 1" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "a∘.+b" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "You should also try similar expressions, such as `a∘.×b`, `a∘.×b` and `a∘.,b`" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "The matrices produced by these \"**outer products**\" are **function tables**, like the **addition table** and **multiplication** table learned in the early school grades." 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "We can decorate such a table with borders to make clear what it represents." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "arg←⍳12\n", 74 | "arg∘.×arg" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "arg,[1]'-',[1]arg∘.×arg" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "('×','-',arg),'|',arg,[1]'-',[1]arg ∘.×arg" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "Other tables have more practical uses:" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "principal←1000×⍳6\n", 109 | "rates←0.01×2+⍳4\n", 110 | "terms←0,⍳6\n", 111 | "2⍕principal∘.×(1+rates)∘.*terms" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "What does that table represent?" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "To understand a more complex expression, first apply it to arguments suitable for getting an idea of its overall behavior. Then see what results from using the same arguments with the first partial expression that APL will execute, and proceed outward (from within parentheses) and leftward, taking progressively larger parts until the full expression is reconstructed. In this way you can learn how the individual parts of the expression combine to produce the final result." 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "n←25\n", 135 | "b←+/[1]+/[3]oil" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "b" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": { 151 | "scrolled": true 152 | }, 153 | "outputs": [], 154 | "source": [ 155 | "countries,'.⎕'[1+b∘.≥(⌈/b)×(⍳n)÷n]" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "Don't spend too much time studying the above before continuing." 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": {}, 168 | "source": [ 169 | "Since `b` is the result of summing `oil` over both months and years, it gives the total imports from each of the six sources over the entire seven-year period. The result of the above expression is a crude barchart of these totals, labelled with the country names. Now let's examine the individual parts of the full expression, giving names to intermediate results that we wish to use as input (arguments) at later stages to make it easier to see what happens at each stage." 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": null, 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "n" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "⊢fractions←(⍳n)÷n" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "⊢highest←⌈/b" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "⊢incs←highest×fractions" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | "⊢spread←b∘.≥incs" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": null, 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "3 21↑1+spread" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "Why did we need to add 1?" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": null, 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [ 239 | "⊢bars←'.⎕'[1+spread]" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "Now we see how the original works by substituting back the original code for each named result we used in our testing." 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": null, 252 | "metadata": {}, 253 | "outputs": [], 254 | "source": [ 255 | "bars←'.⎕'[1+b∘.≥incs]" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": null, 261 | "metadata": {}, 262 | "outputs": [], 263 | "source": [ 264 | "bars←'.⎕'[1+b∘.≥highest×fractions]" 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "execution_count": null, 270 | "metadata": {}, 271 | "outputs": [], 272 | "source": [ 273 | "bars←'.⎕'[1+b∘.≥(⌈/b)×fractions]" 274 | ] 275 | }, 276 | { 277 | "cell_type": "code", 278 | "execution_count": null, 279 | "metadata": {}, 280 | "outputs": [], 281 | "source": [ 282 | "bars←'.⎕'[1+b∘.≥(⌈/b)×(⍳n)÷n]" 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": {}, 288 | "source": [ 289 | "Finally, we turn it into a function, use a different width to show more detail, and add the country labels." 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "metadata": {}, 296 | "outputs": [], 297 | "source": [ 298 | "BarChart←{'.⎕'[1+⍵∘.≥(⌈/⍵)×(⍳⍺)÷⍺]}" 299 | ] 300 | }, 301 | { 302 | "cell_type": "code", 303 | "execution_count": null, 304 | "metadata": {}, 305 | "outputs": [], 306 | "source": [ 307 | "countries,' ',40 BarChart b" 308 | ] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": {}, 313 | "source": [ 314 | "Here’s another expression, written as a function. It produces exactly the same results as your previously defined `Diff`, but it does so rather differently A step-by-step analysis shows how." 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [ 323 | "Diff2←{(d↓⍵)-(-d←⍺=⍳≢⍴⍵)↓⍵}" 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "metadata": {}, 329 | "source": [ 330 | "Start by creating reasonable test arguments, and execute corresponding subexpressions in the APL session." 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": null, 336 | "metadata": {}, 337 | "outputs": [], 338 | "source": [ 339 | "a←3\n", 340 | "w←oil" 341 | ] 342 | }, 343 | { 344 | "cell_type": "code", 345 | "execution_count": null, 346 | "metadata": {}, 347 | "outputs": [], 348 | "source": [ 349 | "(a Diff2 w)≡¯2 -/[a] w" 350 | ] 351 | }, 352 | { 353 | "cell_type": "markdown", 354 | "metadata": {}, 355 | "source": [ 356 | "Starting from the right in the function definition, we see that the first function (`↓`) has a parenthesized expression for a left argument, so that must be evaluated before its value can be used." 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": null, 362 | "metadata": {}, 363 | "outputs": [], 364 | "source": [ 365 | "⍳≢⍴w" 366 | ] 367 | }, 368 | { 369 | "cell_type": "code", 370 | "execution_count": null, 371 | "metadata": {}, 372 | "outputs": [], 373 | "source": [ 374 | "a=⍳≢⍴w" 375 | ] 376 | }, 377 | { 378 | "cell_type": "code", 379 | "execution_count": null, 380 | "metadata": {}, 381 | "outputs": [], 382 | "source": [ 383 | "-d←a=⍳≢⍴w" 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": null, 389 | "metadata": {}, 390 | "outputs": [], 391 | "source": [ 392 | "⍴t←(-d)↓w" 393 | ] 394 | }, 395 | { 396 | "cell_type": "code", 397 | "execution_count": null, 398 | "metadata": {}, 399 | "outputs": [], 400 | "source": [ 401 | "⍴tt←d↓w" 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "metadata": {}, 407 | "source": [ 408 | "Compare `t`, `tt`, and `w`" 409 | ] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": {}, 414 | "source": [ 415 | "Month-to-month changes:" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": null, 421 | "metadata": {}, 422 | "outputs": [], 423 | "source": [ 424 | "(d↓w)-((-d)↓w)" 425 | ] 426 | }, 427 | { 428 | "cell_type": "code", 429 | "execution_count": null, 430 | "metadata": {}, 431 | "outputs": [], 432 | "source": [ 433 | "d←1=⍳≢⍴w" 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": {}, 439 | "source": [ 440 | "Year-to-year changes:" 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "execution_count": null, 446 | "metadata": {}, 447 | "outputs": [], 448 | "source": [ 449 | "(d↓w)-((-d)↓w)" 450 | ] 451 | }, 452 | { 453 | "cell_type": "code", 454 | "execution_count": null, 455 | "metadata": {}, 456 | "outputs": [], 457 | "source": [ 458 | ")erase d" 459 | ] 460 | }, 461 | { 462 | "cell_type": "markdown", 463 | "metadata": {}, 464 | "source": [ 465 | "The **name class** of the name `d`:" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": null, 471 | "metadata": {}, 472 | "outputs": [], 473 | "source": [ 474 | "⎕nc 'd'" 475 | ] 476 | }, 477 | { 478 | "cell_type": "markdown", 479 | "metadata": {}, 480 | "source": [ 481 | "`0` means unassigned." 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": null, 487 | "metadata": {}, 488 | "outputs": [], 489 | "source": [ 490 | "a Diff2 w" 491 | ] 492 | }, 493 | { 494 | "cell_type": "code", 495 | "execution_count": null, 496 | "metadata": {}, 497 | "outputs": [], 498 | "source": [ 499 | "⎕nc 'd'" 500 | ] 501 | }, 502 | { 503 | "cell_type": "markdown", 504 | "metadata": {}, 505 | "source": [ 506 | "`d` is still unassigned" 507 | ] 508 | }, 509 | { 510 | "cell_type": "markdown", 511 | "metadata": {}, 512 | "source": [ 513 | "A name assignment within a dynamically defined function is **local**, existing only within the function when it is executed, and does not affect any **global** (outside the function) assigned values... or lack of assigned values." 514 | ] 515 | } 516 | ], 517 | "metadata": { 518 | "kernelspec": { 519 | "display_name": "Dyalog APL", 520 | "language": "apl", 521 | "name": "dyalog-kernel" 522 | }, 523 | "language_info": { 524 | "file_extension": ".apl", 525 | "mimetype": "text/apl", 526 | "name": "APL" 527 | }, 528 | "tryapl": { 529 | "category": "Introductory Course", 530 | "description": "How to analyse APL code", 531 | "name": "Lesson 14: l) Reading APL Expressions" 532 | } 533 | }, 534 | "nbformat": 4, 535 | "nbformat_minor": 2 536 | } 537 | -------------------------------------------------------------------------------- /Arithmetic Functions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "The arithmetic functions are all **scalar** functions; they penetrate into nested arrays all the way down to the scalars. The standard functions `+`, `-`, `×`, `÷` all act as you might expect:" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [ 15 | { 16 | "data": { 17 | "text/html": [ 18 | "17\n", 19 | "" 20 | ] 21 | }, 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "output_type": "execute_result" 25 | } 26 | ], 27 | "source": [ 28 | "8+9" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 2, 34 | "metadata": {}, 35 | "outputs": [ 36 | { 37 | "data": { 38 | "text/html": [ 39 | "1 ¯3 ¯2\n", 40 | "" 41 | ] 42 | }, 43 | "execution_count": 2, 44 | "metadata": {}, 45 | "output_type": "execute_result" 46 | } 47 | ], 48 | "source": [ 49 | "4 3 2-3 6 4" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/html": [ 60 | "268.55\n", 61 | "" 62 | ] 63 | }, 64 | "execution_count": 3, 65 | "metadata": {}, 66 | "output_type": "execute_result" 67 | } 68 | ], 69 | "source": [ 70 | "length←20.5\n", 71 | "height←13.1\n", 72 | "area←length×height\n", 73 | "area" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 4, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "data": { 83 | "text/html": [ 84 | "┌───────┬───────┬───────┐\n", 85 | "│4 4 0.8│2 0.4 2│0.6 3 3│\n", 86 | "└───────┴───────┴───────┘\n", 87 | "" 88 | ] 89 | }, 90 | "execution_count": 4, 91 | "metadata": {}, 92 | "output_type": "execute_result" 93 | } 94 | ], 95 | "source": [ 96 | "(4 2 3)÷(1 1 5)(1 5 1)(5 1 1)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": {}, 102 | "source": [ 103 | "All of those functions can also be applied monadically. For example `-x` is negative `x` (or `0-x`). `÷x` is the reciprocal of `x` (or `1÷x`)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 5, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "data": { 113 | "text/html": [ 114 | "¯3 1 ¯4 1 ¯5\n", 115 | "" 116 | ] 117 | }, 118 | "execution_count": 5, 119 | "metadata": {}, 120 | "output_type": "execute_result" 121 | } 122 | ], 123 | "source": [ 124 | "-3 ¯1 4 ¯1 5" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 6, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "data": { 134 | "text/html": [ 135 | "0.333333\n", 136 | "" 137 | ] 138 | }, 139 | "execution_count": 6, 140 | "metadata": {}, 141 | "output_type": "execute_result" 142 | } 143 | ], 144 | "source": [ 145 | "÷3" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "Monadic `+` and `×` are designed for complex numbers. `+` gives the complex conjugate. `×` gives a complex number with magnitude 1 (unless it is applied to `0`) in the direction of its argument. For real numbers, `+` has no effect, and `×` gives the sign of its argument." 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 7, 158 | "metadata": {}, 159 | "outputs": [ 160 | { 161 | "data": { 162 | "text/html": [ 163 | "1J¯2 0J1 4 3J¯3\n", 164 | "" 165 | ] 166 | }, 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "+1j2 0j¯1 4 3j3" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 8, 179 | "metadata": {}, 180 | "outputs": [ 181 | { 182 | "data": { 183 | "text/html": [ 184 | "1 0.707107J0.707107 0.707107J0.707107 0.341743J¯0.939793 ¯1 0\n", 185 | "" 186 | ] 187 | }, 188 | "execution_count": 8, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "×10 3j3 4j4 8j¯22 ¯3 0" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "`*` is the power function. `X*Y` is `X` to the power of `Y`" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 9, 207 | "metadata": {}, 208 | "outputs": [ 209 | { 210 | "data": { 211 | "text/html": [ 212 | "2.197\n", 213 | "" 214 | ] 215 | }, 216 | "execution_count": 9, 217 | "metadata": {}, 218 | "output_type": "execute_result" 219 | } 220 | ], 221 | "source": [ 222 | "1.3×1.3×1.3" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 10, 228 | "metadata": {}, 229 | "outputs": [ 230 | { 231 | "data": { 232 | "text/html": [ 233 | "2.197\n", 234 | "" 235 | ] 236 | }, 237 | "execution_count": 10, 238 | "metadata": {}, 239 | "output_type": "execute_result" 240 | } 241 | ], 242 | "source": [ 243 | "1.3*3" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 11, 249 | "metadata": {}, 250 | "outputs": [ 251 | { 252 | "data": { 253 | "text/html": [ 254 | "3\n", 255 | "" 256 | ] 257 | }, 258 | "execution_count": 11, 259 | "metadata": {}, 260 | "output_type": "execute_result" 261 | } 262 | ], 263 | "source": [ 264 | "9*0.5 ⍝ square root" 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "execution_count": 12, 270 | "metadata": {}, 271 | "outputs": [ 272 | { 273 | "data": { 274 | "text/html": [ 275 | "0.05\n", 276 | "" 277 | ] 278 | }, 279 | "execution_count": 12, 280 | "metadata": {}, 281 | "output_type": "execute_result" 282 | } 283 | ], 284 | "source": [ 285 | "20*¯1 ⍝ reciprocal" 286 | ] 287 | }, 288 | { 289 | "cell_type": "markdown", 290 | "metadata": {}, 291 | "source": [ 292 | "Monadically, `*x` is *e* to the power of `x`." 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": 13, 298 | "metadata": {}, 299 | "outputs": [ 300 | { 301 | "data": { 302 | "text/html": [ 303 | "24.5325 24.5325\n", 304 | "" 305 | ] 306 | }, 307 | "execution_count": 13, 308 | "metadata": {}, 309 | "output_type": "execute_result" 310 | } 311 | ], 312 | "source": [ 313 | "e←2.71828182845\n", 314 | "(e*3.2) (*3.2)" 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": {}, 320 | "source": [ 321 | "A close relative of `*` is `⍟` which is logarithm. `a⍟b` is the base-`a` logarithm of `b`." 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 14, 327 | "metadata": {}, 328 | "outputs": [ 329 | { 330 | "data": { 331 | "text/html": [ 332 | "6\n", 333 | "" 334 | ] 335 | }, 336 | "execution_count": 14, 337 | "metadata": {}, 338 | "output_type": "execute_result" 339 | } 340 | ], 341 | "source": [ 342 | "2⍟64" 343 | ] 344 | }, 345 | { 346 | "cell_type": "markdown", 347 | "metadata": {}, 348 | "source": [ 349 | "As a monad, `⍟x` is the natural logarithm of `x` (or `e⍟x`)." 350 | ] 351 | }, 352 | { 353 | "cell_type": "code", 354 | "execution_count": 15, 355 | "metadata": {}, 356 | "outputs": [ 357 | { 358 | "data": { 359 | "text/html": [ 360 | "0\n", 361 | "" 362 | ] 363 | }, 364 | "execution_count": 15, 365 | "metadata": {}, 366 | "output_type": "execute_result" 367 | } 368 | ], 369 | "source": [ 370 | "⍟1" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": 16, 376 | "metadata": {}, 377 | "outputs": [ 378 | { 379 | "data": { 380 | "text/html": [ 381 | "23.14\n", 382 | "" 383 | ] 384 | }, 385 | "execution_count": 16, 386 | "metadata": {}, 387 | "output_type": "execute_result" 388 | } 389 | ], 390 | "source": [ 391 | "⍟(*23.14)" 392 | ] 393 | }, 394 | { 395 | "cell_type": "markdown", 396 | "metadata": {}, 397 | "source": [ 398 | "`a⌈b`, gives the maximum of `a` and `b`. While `⌈x` is the ceiling of `x`, that is, the smallest integer larger than `x`." 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": 17, 404 | "metadata": {}, 405 | "outputs": [ 406 | { 407 | "data": { 408 | "text/html": [ 409 | "4 4 2 0 0 0\n", 410 | "" 411 | ] 412 | }, 413 | "execution_count": 17, 414 | "metadata": {}, 415 | "output_type": "execute_result" 416 | } 417 | ], 418 | "source": [ 419 | "4 4 2 ¯4 0 ¯10 ⌈ 0" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": 18, 425 | "metadata": {}, 426 | "outputs": [ 427 | { 428 | "data": { 429 | "text/html": [ 430 | "2 3 0 6 ¯2\n", 431 | "" 432 | ] 433 | }, 434 | "execution_count": 18, 435 | "metadata": {}, 436 | "output_type": "execute_result" 437 | } 438 | ], 439 | "source": [ 440 | "⌈1.5 3 ¯0.3 5.0001 ¯2.7" 441 | ] 442 | }, 443 | { 444 | "cell_type": "markdown", 445 | "metadata": {}, 446 | "source": [ 447 | "After seeing what `⌈` does, it is not hard to guess what `⌊` does. It is of course *minimum* and *floor*" 448 | ] 449 | }, 450 | { 451 | "cell_type": "code", 452 | "execution_count": 19, 453 | "metadata": {}, 454 | "outputs": [ 455 | { 456 | "data": { 457 | "text/html": [ 458 | "¯2 2 5\n", 459 | "" 460 | ] 461 | }, 462 | "execution_count": 19, 463 | "metadata": {}, 464 | "output_type": "execute_result" 465 | } 466 | ], 467 | "source": [ 468 | "3 2 10⌊¯2 5 5" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 20, 474 | "metadata": {}, 475 | "outputs": [ 476 | { 477 | "data": { 478 | "text/html": [ 479 | "1 ¯7 5\n", 480 | "" 481 | ] 482 | }, 483 | "execution_count": 20, 484 | "metadata": {}, 485 | "output_type": "execute_result" 486 | } 487 | ], 488 | "source": [ 489 | "⌊1.4 ¯6.02 5" 490 | ] 491 | }, 492 | { 493 | "cell_type": "markdown", 494 | "metadata": {}, 495 | "source": [ 496 | "Numbers can be rounded to the nearest integer with `⌊0.5+`. You can see it highlighted below because it is an idiom, recognised and optimised by the interpreter." 497 | ] 498 | }, 499 | { 500 | "cell_type": "code", 501 | "execution_count": 21, 502 | "metadata": {}, 503 | "outputs": [ 504 | { 505 | "data": { 506 | "text/html": [ 507 | "3 4 7 1\n", 508 | "" 509 | ] 510 | }, 511 | "execution_count": 21, 512 | "metadata": {}, 513 | "output_type": "execute_result" 514 | } 515 | ], 516 | "source": [ 517 | "⌊0.5+3.3 3.7 6.5 1" 518 | ] 519 | }, 520 | { 521 | "cell_type": "markdown", 522 | "metadata": {}, 523 | "source": [ 524 | "Monadically, `|x` gives the magnitude of `x`. For real numbers, this is the absolute value." 525 | ] 526 | }, 527 | { 528 | "cell_type": "code", 529 | "execution_count": 22, 530 | "metadata": {}, 531 | "outputs": [ 532 | { 533 | "data": { 534 | "text/html": [ 535 | "2 3 4 0 10.5\n", 536 | "" 537 | ] 538 | }, 539 | "execution_count": 22, 540 | "metadata": {}, 541 | "output_type": "execute_result" 542 | } 543 | ], 544 | "source": [ 545 | "| 2 ¯3 4 0 ¯10.5" 546 | ] 547 | }, 548 | { 549 | "cell_type": "code", 550 | "execution_count": 23, 551 | "metadata": {}, 552 | "outputs": [ 553 | { 554 | "data": { 555 | "text/html": [ 556 | "5\n", 557 | "" 558 | ] 559 | }, 560 | "execution_count": 23, 561 | "metadata": {}, 562 | "output_type": "execute_result" 563 | } 564 | ], 565 | "source": [ 566 | "| 3j4" 567 | ] 568 | }, 569 | { 570 | "cell_type": "markdown", 571 | "metadata": {}, 572 | "source": [ 573 | "Dyadically, `|` is residue. `x|y` is the remainder when `y` is divided by `x`." 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": 24, 579 | "metadata": {}, 580 | "outputs": [ 581 | { 582 | "data": { 583 | "text/html": [ 584 | "0 1 2 0 1 2 0 1\n", 585 | "" 586 | ] 587 | }, 588 | "execution_count": 24, 589 | "metadata": {}, 590 | "output_type": "execute_result" 591 | } 592 | ], 593 | "source": [ 594 | "3|0 1 2 3 4 5 6 7" 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": 25, 600 | "metadata": {}, 601 | "outputs": [ 602 | { 603 | "data": { 604 | "text/html": [ 605 | "0 0.4 0.31 0.2\n", 606 | "" 607 | ] 608 | }, 609 | "execution_count": 25, 610 | "metadata": {}, 611 | "output_type": "execute_result" 612 | } 613 | ], 614 | "source": [ 615 | "1|2 3.4 0.31 5.2 ⍝ The fractional parts of each number" 616 | ] 617 | } 618 | ], 619 | "metadata": { 620 | "kernelspec": { 621 | "display_name": "Dyalog APL", 622 | "language": "apl", 623 | "name": "dyalog-kernel" 624 | }, 625 | "language_info": { 626 | "file_extension": ".apl", 627 | "mimetype": "text/apl", 628 | "name": "APL" 629 | }, 630 | "tryapl": { 631 | "category": "Closer Looks at Some Functions", 632 | "description": "Doing mathematics in APL", 633 | "name": "Arithmetic Functions: + - × ÷ * ⍟ ⌈ ⌊ |" 634 | } 635 | }, 636 | "nbformat": 4, 637 | "nbformat_minor": 2 638 | } 639 | -------------------------------------------------------------------------------- /New in v16.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Monadic function `⍸`\n", 8 | "*Where* returns the indices of the 1s in the Boolean argument:" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "data": { 18 | "text/html": [ 19 | "1 3 4 7\n", 20 | "" 21 | ] 22 | }, 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "output_type": "execute_result" 26 | } 27 | ], 28 | "source": [ 29 | "⍸1 0 1 1 0 0 1" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 2, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/html": [ 40 | "1 0 1\n", 41 | "1 1 0\n", 42 | "" 43 | ] 44 | }, 45 | "execution_count": 2, 46 | "metadata": {}, 47 | "output_type": "execute_result" 48 | }, 49 | { 50 | "data": { 51 | "text/html": [ 52 | "┌───┬───┬───┬───┐\n", 53 | "│1 1│1 3│2 1│2 2│\n", 54 | "└───┴───┴───┴───┘\n", 55 | "" 56 | ] 57 | }, 58 | "execution_count": 2, 59 | "metadata": {}, 60 | "output_type": "execute_result" 61 | } 62 | ], 63 | "source": [ 64 | "M←2 3⍴1 0 1 1\n", 65 | "M\n", 66 | "⍸M" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "### Dyadic function `⍸`\n", 74 | "*Interval index* takes a list of sorted arrays on the left, and for each array on the right, tells which \"gap\" (interval) it belongs to:" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 3, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "data": { 84 | "text/html": [ 85 | "0 3 4 1 2\n", 86 | "" 87 | ] 88 | }, 89 | "execution_count": 3, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "1 10 100 1000⍸0 500 2000 3 10 " 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "So 0 is in interval number 0 (that is, before 1–10). 500 is in interval 3, which is 100–1000, etc. " 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "### Monadic function `⊆`\n", 110 | "This one is called *Nest* because it guarantees you that the result is nested (non-simple).\n", 111 | "`(1 2)(3 4 5)` is already nested, so `⊆` won't do anything: " 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 4, 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "data": { 121 | "text/html": [ 122 | "┌───┬─────┐\n", 123 | "│1 2│3 4 5│\n", 124 | "└───┴─────┘\n", 125 | "" 126 | ] 127 | }, 128 | "execution_count": 4, 129 | "metadata": {}, 130 | "output_type": "execute_result" 131 | }, 132 | { 133 | "data": { 134 | "text/html": [ 135 | "┌───┬─────┐\n", 136 | "│1 2│3 4 5│\n", 137 | "└───┴─────┘\n", 138 | "" 139 | ] 140 | }, 141 | "execution_count": 4, 142 | "metadata": {}, 143 | "output_type": "execute_result" 144 | } 145 | ], 146 | "source": [ 147 | "(1 2)(3 4 5)\n", 148 | "⊆(1 2)(3 4 5)" 149 | ] 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "metadata": {}, 154 | "source": [ 155 | "`1 2 3` is not nested, so `⊆` will nest it:" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 5, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "text/html": [ 166 | "1 2 3\n", 167 | "" 168 | ] 169 | }, 170 | "execution_count": 5, 171 | "metadata": {}, 172 | "output_type": "execute_result" 173 | }, 174 | { 175 | "data": { 176 | "text/html": [ 177 | "┌─────┐\n", 178 | "│1 2 3│\n", 179 | "└─────┘\n", 180 | "" 181 | ] 182 | }, 183 | "execution_count": 5, 184 | "metadata": {}, 185 | "output_type": "execute_result" 186 | } 187 | ], 188 | "source": [ 189 | "1 2 3\n", 190 | "⊆1 2 3" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": {}, 196 | "source": [ 197 | "### Dyadic function `⊆`\n", 198 | "*Partition* was formerly only available as `{⎕ML←3 ⋄ ⍺⊂⍵}`. It partitions its right argument letting a new partition begin whenever an element is higher than its neighbour in the left. Also, elements indicated by 0s are dropped completely:" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 6, 204 | "metadata": {}, 205 | "outputs": [ 206 | { 207 | "data": { 208 | "text/html": [ 209 | "┌─┬──┬───┬──┐\n", 210 | "│H│lo│ Wo│rl│\n", 211 | "└─┴──┴───┴──┘\n", 212 | "" 213 | ] 214 | }, 215 | "execution_count": 6, 216 | "metadata": {}, 217 | "output_type": "execute_result" 218 | } 219 | ], 220 | "source": [ 221 | "1 0 0 1 1 3 2 2 5 5 0⊆'Hello World'" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "metadata": {}, 227 | "source": [ 228 | "### Dyadic operator `@`\n", 229 | "The *At* operator does exactly what it says. What's on its left gets done **at** the position indicated by its right operand:" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 7, 235 | "metadata": {}, 236 | "outputs": [ 237 | { 238 | "data": { 239 | "text/html": [ 240 | "HXllX\n", 241 | "" 242 | ] 243 | }, 244 | "execution_count": 7, 245 | "metadata": {}, 246 | "output_type": "execute_result" 247 | } 248 | ], 249 | "source": [ 250 | "('X'@2 5) 'Hello'" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "We can also give an array which matches the selected elements:" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 8, 263 | "metadata": {}, 264 | "outputs": [ 265 | { 266 | "data": { 267 | "text/html": [ 268 | "HXllY\n", 269 | "" 270 | ] 271 | }, 272 | "execution_count": 8, 273 | "metadata": {}, 274 | "output_type": "execute_result" 275 | } 276 | ], 277 | "source": [ 278 | "('XY'@2 5) 'Hello'" 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "metadata": {}, 284 | "source": [ 285 | "We can also use it to modify rather than replace elements:" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": 9, 291 | "metadata": {}, 292 | "outputs": [ 293 | { 294 | "data": { 295 | "text/html": [ 296 | "10 ¯20 30 40 ¯50 60\n", 297 | "" 298 | ] 299 | }, 300 | "execution_count": 9, 301 | "metadata": {}, 302 | "output_type": "execute_result" 303 | } 304 | ], 305 | "source": [ 306 | "(-@2 5) 10 20 30 40 50 60" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": 10, 312 | "metadata": {}, 313 | "outputs": [ 314 | { 315 | "data": { 316 | "text/html": [ 317 | "10 27 30 40 57 60\n", 318 | "" 319 | ] 320 | }, 321 | "execution_count": 10, 322 | "metadata": {}, 323 | "output_type": "execute_result" 324 | } 325 | ], 326 | "source": [ 327 | "7 (+@2 5) 10 20 30 40 50 60" 328 | ] 329 | }, 330 | { 331 | "cell_type": "markdown", 332 | "metadata": {}, 333 | "source": [ 334 | "If we use a function right operand, it gets applied to the right argument, and the result must be a Boolean mask which then used instead of the list of indices." 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": 11, 340 | "metadata": {}, 341 | "outputs": [ 342 | { 343 | "data": { 344 | "text/html": [ 345 | "1 0 0 0 0 0 1 0 0 0 0\n", 346 | "" 347 | ] 348 | }, 349 | "execution_count": 11, 350 | "metadata": {}, 351 | "output_type": "execute_result" 352 | } 353 | ], 354 | "source": [ 355 | "(∊∘⎕A) 'Hello World' ⍝ ⎕A is the uppercase alphabet" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": 12, 361 | "metadata": {}, 362 | "outputs": [ 363 | { 364 | "data": { 365 | "text/html": [ 366 | "xello xorld\n", 367 | "" 368 | ] 369 | }, 370 | "execution_count": 12, 371 | "metadata": {}, 372 | "output_type": "execute_result" 373 | } 374 | ], 375 | "source": [ 376 | "'x'@(∊∘⎕A) 'Hello World' ⍝ replace those" 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "### Dyadic operator `⌺`\n", 384 | "*Stencil* (as in [stencil code](https://en.wikipedia.org/wiki/Stencil_code)) and the symbol is supposed to evoke the picture of a stencil over a paper. It takes a function left operand and an array right operand, and derives a monadic function.\n", 385 | "\n", 386 | "The right operand specifies what neighbourhoods to apply to. E.g. in Game of Life, the neighbourhoods are 3-by-3 sub-matrices centred on each element in the input array. The function operand gets called dyadically with the right argument being a neighbourhood and the argument left being information about whether he neighbourhood overlaps an edge of the original argument world.\n", 387 | "\n", 388 | "To see how it works, we'll use `{⊂⍵}` as left operand. It just encloses the right argument (`⍵`, that is, the neighbourhood) so we can see it. As right operand (neighbourhood size) we use `3 3`." 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": 13, 394 | "metadata": {}, 395 | "outputs": [ 396 | { 397 | "data": { 398 | "text/html": [ 399 | "ABCDEF\n", 400 | "GHIJKL\n", 401 | "MNOPQR\n", 402 | "STUVWX\n", 403 | "" 404 | ] 405 | }, 406 | "execution_count": 13, 407 | "metadata": {}, 408 | "output_type": "execute_result" 409 | } 410 | ], 411 | "source": [ 412 | "4 6⍴⎕A ⍝ our world" 413 | ] 414 | }, 415 | { 416 | "cell_type": "code", 417 | "execution_count": 14, 418 | "metadata": {}, 419 | "outputs": [ 420 | { 421 | "data": { 422 | "text/html": [ 423 | "┌───┬───┬───┬───┬───┬───┐\n", 424 | "│ │ │ │ │ │ │\n", 425 | "│ AB│ABC│BCD│CDE│DEF│EF │\n", 426 | "│ GH│GHI│HIJ│IJK│JKL│KL │\n", 427 | "├───┼───┼───┼───┼───┼───┤\n", 428 | "│ AB│ABC│BCD│CDE│DEF│EF │\n", 429 | "│ GH│GHI│HIJ│IJK│JKL│KL │\n", 430 | "│ MN│MNO│NOP│OPQ│PQR│QR │\n", 431 | "├───┼───┼───┼───┼───┼───┤\n", 432 | "│ GH│GHI│HIJ│IJK│JKL│KL │\n", 433 | "│ MN│MNO│NOP│OPQ│PQR│QR │\n", 434 | "│ ST│STU│TUV│UVW│VWX│WX │\n", 435 | "├───┼───┼───┼───┼───┼───┤\n", 436 | "│ MN│MNO│NOP│OPQ│PQR│QR │\n", 437 | "│ ST│STU│TUV│UVW│VWX│WX │\n", 438 | "│ │ │ │ │ │ │\n", 439 | "└───┴───┴───┴───┴───┴───┘\n", 440 | "" 441 | ] 442 | }, 443 | "execution_count": 14, 444 | "metadata": {}, 445 | "output_type": "execute_result" 446 | } 447 | ], 448 | "source": [ 449 | "({⊂⍵}⌺3 3) 4 6⍴⎕A ⍝ the neighbourhoods" 450 | ] 451 | }, 452 | { 453 | "cell_type": "markdown", 454 | "metadata": {}, 455 | "source": [ 456 | "We got a 4-by-6 matrix of neighbourhoods back. Notice that all the neighbourhoods are 3-by-3, even at the edges, at which they were padded with spaces. The padding was done sometimes on top, sometimes on the left, sometimes on the right, and sometimes on the bottom. The information about that is in the left argument (`⍺`) of the operand function:" 457 | ] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "execution_count": 15, 462 | "metadata": {}, 463 | "outputs": [ 464 | { 465 | "data": { 466 | "text/html": [ 467 | "┌────┬────┬────┬────┬────┬─────┐\n", 468 | "│1 1 │1 0 │1 0 │1 0 │1 0 │1 ¯1 │\n", 469 | "├────┼────┼────┼────┼────┼─────┤\n", 470 | "│0 1 │0 0 │0 0 │0 0 │0 0 │0 ¯1 │\n", 471 | "├────┼────┼────┼────┼────┼─────┤\n", 472 | "│0 1 │0 0 │0 0 │0 0 │0 0 │0 ¯1 │\n", 473 | "├────┼────┼────┼────┼────┼─────┤\n", 474 | "│¯1 1│¯1 0│¯1 0│¯1 0│¯1 0│¯1 ¯1│\n", 475 | "└────┴────┴────┴────┴────┴─────┘\n", 476 | "" 477 | ] 478 | }, 479 | "execution_count": 15, 480 | "metadata": {}, 481 | "output_type": "execute_result" 482 | } 483 | ], 484 | "source": [ 485 | "({⊂⍺}⌺3 3) 4 6⍴⎕A" 486 | ] 487 | }, 488 | { 489 | "cell_type": "markdown", 490 | "metadata": {}, 491 | "source": [ 492 | "So, each cell contains two elements, one for rows, and one for columns. Positive indicates left/top. Negative is right/bottom. The magnitude indicates how many rows/columns were padded. This fits nicely with dyadic `↓` (*Drop*), which as left argument takes the number of (rows,columns) to drop from its right argument:" 493 | ] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "execution_count": 16, 498 | "metadata": {}, 499 | "outputs": [ 500 | { 501 | "data": { 502 | "text/html": [ 503 | "┌──┬───┬───┬───┬───┬──┐\n", 504 | "│AB│ABC│BCD│CDE│DEF│EF│\n", 505 | "│GH│GHI│HIJ│IJK│JKL│KL│\n", 506 | "├──┼───┼───┼───┼───┼──┤\n", 507 | "│AB│ABC│BCD│CDE│DEF│EF│\n", 508 | "│GH│GHI│HIJ│IJK│JKL│KL│\n", 509 | "│MN│MNO│NOP│OPQ│PQR│QR│\n", 510 | "├──┼───┼───┼───┼───┼──┤\n", 511 | "│GH│GHI│HIJ│IJK│JKL│KL│\n", 512 | "│MN│MNO│NOP│OPQ│PQR│QR│\n", 513 | "│ST│STU│TUV│UVW│VWX│WX│\n", 514 | "├──┼───┼───┼───┼───┼──┤\n", 515 | "│MN│MNO│NOP│OPQ│PQR│QR│\n", 516 | "│ST│STU│TUV│UVW│VWX│WX│\n", 517 | "└──┴───┴───┴───┴───┴──┘\n", 518 | "" 519 | ] 520 | }, 521 | "execution_count": 16, 522 | "metadata": {}, 523 | "output_type": "execute_result" 524 | } 525 | ], 526 | "source": [ 527 | "({⊂⍺↓⍵}⌺3 3) 4 6⍴⎕A" 528 | ] 529 | } 530 | ], 531 | "metadata": { 532 | "kernelspec": { 533 | "display_name": "Dyalog APL", 534 | "language": "apl", 535 | "name": "dyalog-kernel" 536 | }, 537 | "language_info": { 538 | "file_extension": ".apl", 539 | "mimetype": "text/apl", 540 | "name": "APL" 541 | }, 542 | "tryapl": { 543 | "category": "Highlights of Recent Releases", 544 | "description": "Language extensions in Dyalog APL version 16.0", 545 | "name": "New in version 16.0" 546 | } 547 | }, 548 | "nbformat": 4, 549 | "nbformat_minor": 2 550 | } 551 | -------------------------------------------------------------------------------- /APL Expressions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "APL is a mathematical notation which just happens to be machine executable, i.e. be **A** **P**rogramming **L**anguage. APL expressions consist of *functions*, *arrays* and *assignments*. They may also have trailing *comments*, beginning with the lamp symbol `⍝` (a glowing bulb filament to enlighten you)." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "⍝ This is a comment - nothing happens" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "You can have multiple expressions on a single line by separating them with a diamond:" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "metadata": {}, 30 | "outputs": [ 31 | { 32 | "data": { 33 | "text/html": [ 34 | "4\n", 35 | "6\n", 36 | "" 37 | ] 38 | }, 39 | "execution_count": 2, 40 | "metadata": {}, 41 | "output_type": "execute_result" 42 | } 43 | ], 44 | "source": [ 45 | "2+2 ⋄ 3+3" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "## Functions\n", 53 | "We call all code that can be applied to data *functions*, even *primitive* built-in things. So `+` and `f` in `f(x)` are both functions. (APL *operators* are something else.)" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 3, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "text/html": [ 64 | "+\n", 65 | "" 66 | ] 67 | }, 68 | "execution_count": 3, 69 | "metadata": {}, 70 | "output_type": "execute_result" 71 | } 72 | ], 73 | "source": [ 74 | "+" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 4, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "data": { 84 | "text/html": [ 85 | "3\n", 86 | "" 87 | ] 88 | }, 89 | "execution_count": 4, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "5-2" 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "Many APL functions can be applied as prefix (monadically) or infix (dyadically). Usually, the monadic and dyadic forms are closely related. E.g. `-b` is `0-b`:" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 5, 108 | "metadata": {}, 109 | "outputs": [ 110 | { 111 | "data": { 112 | "text/html": [ 113 | "¯3\n", 114 | "" 115 | ] 116 | }, 117 | "execution_count": 5, 118 | "metadata": {}, 119 | "output_type": "execute_result" 120 | } 121 | ], 122 | "source": [ 123 | "-3 ⍝ APL uses high minus to indicate negative numbers" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "## Arrays\n", 131 | "All data resides in *arrays*. An array is a rectangular collection of numbers, characters and arrays, arranged along zero or more axes. We can use more specific terms for some arrays, like a single number is a *scalar*, a list is a *vector*, and 2D arrays are *matrices*. Vectors can be formed by just placing elements next to each other:" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 6, 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "data": { 141 | "text/html": [ 142 | "1 2 3\n", 143 | "" 144 | ] 145 | }, 146 | "execution_count": 6, 147 | "metadata": {}, 148 | "output_type": "execute_result" 149 | } 150 | ], 151 | "source": [ 152 | "1 2 3" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "### Strings\n", 160 | "As APL has no string data type, we just use character vectors (lists) instead. Characters and character vectors are in single quotes:" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 7, 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "data": { 170 | "text/html": [ 171 | "a\n", 172 | "" 173 | ] 174 | }, 175 | "execution_count": 7, 176 | "metadata": {}, 177 | "output_type": "execute_result" 178 | } 179 | ], 180 | "source": [ 181 | "'a'" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 8, 187 | "metadata": {}, 188 | "outputs": [ 189 | { 190 | "data": { 191 | "text/html": [ 192 | "Hello, World!\n", 193 | "" 194 | ] 195 | }, 196 | "execution_count": 8, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "'Hello, World!' ⍝ a famous program written in APL!" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "### Numbers\n", 210 | "A number is a number is a number: You don't have to deal with internal representation as APL will internally convert between bit-Booleans, integers (of various sizes), floats, base-10 decimal floats, and complex numbers — all seamless to you:" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 9, 216 | "metadata": {}, 217 | "outputs": [ 218 | { 219 | "data": { 220 | "text/html": [ 221 | "1\n", 222 | "" 223 | ] 224 | }, 225 | "execution_count": 9, 226 | "metadata": {}, 227 | "output_type": "execute_result" 228 | } 229 | ], 230 | "source": [ 231 | "5>4" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": 10, 237 | "metadata": {}, 238 | "outputs": [ 239 | { 240 | "data": { 241 | "text/html": [ 242 | "3\n", 243 | "" 244 | ] 245 | }, 246 | "execution_count": 10, 247 | "metadata": {}, 248 | "output_type": "execute_result" 249 | } 250 | ], 251 | "source": [ 252 | "2+(5>4)" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": 11, 258 | "metadata": {}, 259 | "outputs": [ 260 | { 261 | "data": { 262 | "text/html": [ 263 | "0.666667\n", 264 | "" 265 | ] 266 | }, 267 | "execution_count": 11, 268 | "metadata": {}, 269 | "output_type": "execute_result" 270 | } 271 | ], 272 | "source": [ 273 | "2÷3" 274 | ] 275 | }, 276 | { 277 | "cell_type": "code", 278 | "execution_count": 12, 279 | "metadata": {}, 280 | "outputs": [ 281 | { 282 | "data": { 283 | "text/html": [ 284 | "1.66667\n", 285 | "" 286 | ] 287 | }, 288 | "execution_count": 12, 289 | "metadata": {}, 290 | "output_type": "execute_result" 291 | } 292 | ], 293 | "source": [ 294 | "1+(2÷3)" 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "metadata": {}, 300 | "source": [ 301 | "APL takes care of binary-vs-decimal inexactness too, so 3×(1÷3) is really 1:" 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": 13, 307 | "metadata": {}, 308 | "outputs": [ 309 | { 310 | "data": { 311 | "text/html": [ 312 | "1\n", 313 | "" 314 | ] 315 | }, 316 | "execution_count": 13, 317 | "metadata": {}, 318 | "output_type": "execute_result" 319 | } 320 | ], 321 | "source": [ 322 | "3×(1÷3)" 323 | ] 324 | }, 325 | { 326 | "cell_type": "markdown", 327 | "metadata": {}, 328 | "source": [ 329 | "Negative numbers are indicated by a high minus:" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 14, 335 | "metadata": {}, 336 | "outputs": [ 337 | { 338 | "data": { 339 | "text/html": [ 340 | "¯2\n", 341 | "" 342 | ] 343 | }, 344 | "execution_count": 14, 345 | "metadata": {}, 346 | "output_type": "execute_result" 347 | } 348 | ], 349 | "source": [ 350 | "3-5" 351 | ] 352 | }, 353 | { 354 | "cell_type": "markdown", 355 | "metadata": {}, 356 | "source": [ 357 | "Very large or small numbers use exponential notation, separating the significand from the mantissa with an `E`. In other words, an `E` embedded in a number reads as *times-ten-to-the-power-of*:" 358 | ] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "execution_count": 15, 363 | "metadata": {}, 364 | "outputs": [ 365 | { 366 | "data": { 367 | "text/html": [ 368 | "1E12\n", 369 | "" 370 | ] 371 | }, 372 | "execution_count": 15, 373 | "metadata": {}, 374 | "output_type": "execute_result" 375 | } 376 | ], 377 | "source": [ 378 | "1000×1000×1000×1000" 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": 16, 384 | "metadata": {}, 385 | "outputs": [ 386 | { 387 | "data": { 388 | "text/html": [ 389 | "0.000001\n", 390 | "" 391 | ] 392 | }, 393 | "execution_count": 16, 394 | "metadata": {}, 395 | "output_type": "execute_result" 396 | } 397 | ], 398 | "source": [ 399 | "1e¯6" 400 | ] 401 | }, 402 | { 403 | "cell_type": "markdown", 404 | "metadata": {}, 405 | "source": [ 406 | "Complex numbers are similar in that they use a `J` to separate the real and imaginary parts:" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 17, 412 | "metadata": {}, 413 | "outputs": [ 414 | { 415 | "data": { 416 | "text/html": [ 417 | "¯2\n", 418 | "" 419 | ] 420 | }, 421 | "execution_count": 17, 422 | "metadata": {}, 423 | "output_type": "execute_result" 424 | } 425 | ], 426 | "source": [ 427 | "0j1×0j2" 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": 18, 433 | "metadata": {}, 434 | "outputs": [ 435 | { 436 | "data": { 437 | "text/html": [ 438 | "0J5\n", 439 | "" 440 | ] 441 | }, 442 | "execution_count": 18, 443 | "metadata": {}, 444 | "output_type": "execute_result" 445 | } 446 | ], 447 | "source": [ 448 | "1j2×2j1" 449 | ] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "metadata": {}, 454 | "source": [ 455 | "## Assignments\n", 456 | "You can assign a function or an array to a name using `←`:" 457 | ] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "execution_count": 19, 462 | "metadata": {}, 463 | "outputs": [ 464 | { 465 | "data": { 466 | "text/html": [ 467 | "5\n", 468 | "" 469 | ] 470 | }, 471 | "execution_count": 19, 472 | "metadata": {}, 473 | "output_type": "execute_result" 474 | } 475 | ], 476 | "source": [ 477 | "plus←+\n", 478 | "two←2\n", 479 | "three←3\n", 480 | "two plus three" 481 | ] 482 | }, 483 | { 484 | "cell_type": "markdown", 485 | "metadata": {}, 486 | "source": [ 487 | "This avoids all confusion of assignment with equality. `=` is just another comparison function:" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": 20, 493 | "metadata": {}, 494 | "outputs": [ 495 | { 496 | "data": { 497 | "text/html": [ 498 | "0\n", 499 | "" 500 | ] 501 | }, 502 | "execution_count": 20, 503 | "metadata": {}, 504 | "output_type": "execute_result" 505 | } 506 | ], 507 | "source": [ 508 | "two=three" 509 | ] 510 | }, 511 | { 512 | "cell_type": "code", 513 | "execution_count": 21, 514 | "metadata": {}, 515 | "outputs": [ 516 | { 517 | "data": { 518 | "text/html": [ 519 | "1\n", 520 | "" 521 | ] 522 | }, 523 | "execution_count": 21, 524 | "metadata": {}, 525 | "output_type": "execute_result" 526 | } 527 | ], 528 | "source": [ 529 | "two=2" 530 | ] 531 | }, 532 | { 533 | "cell_type": "markdown", 534 | "metadata": {}, 535 | "source": [ 536 | "## Why use APL instead of conventional mathematical notation?\n", 537 | "Mathematics has some inconsistent and weird notations, like negation and factorial being on opposite sides of their argument, exponentiation doesn't have a symbol (rather the exponent is raised and made smaller) and magnitude has two symbols (a vertical bar on each side). APL harmonises everything to be in-line pre/infix single-symbols, so factorial is `!b`, raising to a power is `a*b`, and magnitude (absolute value) is `|b`:" 538 | ] 539 | }, 540 | { 541 | "cell_type": "code", 542 | "execution_count": 22, 543 | "metadata": {}, 544 | "outputs": [ 545 | { 546 | "data": { 547 | "text/html": [ 548 | "120\n", 549 | "" 550 | ] 551 | }, 552 | "execution_count": 22, 553 | "metadata": {}, 554 | "output_type": "execute_result" 555 | } 556 | ], 557 | "source": [ 558 | "!5" 559 | ] 560 | }, 561 | { 562 | "cell_type": "code", 563 | "execution_count": 23, 564 | "metadata": {}, 565 | "outputs": [ 566 | { 567 | "data": { 568 | "text/html": [ 569 | "9\n", 570 | "" 571 | ] 572 | }, 573 | "execution_count": 23, 574 | "metadata": {}, 575 | "output_type": "execute_result" 576 | } 577 | ], 578 | "source": [ 579 | "3*2" 580 | ] 581 | }, 582 | { 583 | "cell_type": "code", 584 | "execution_count": 24, 585 | "metadata": {}, 586 | "outputs": [ 587 | { 588 | "data": { 589 | "text/html": [ 590 | "5\n", 591 | "" 592 | ] 593 | }, 594 | "execution_count": 24, 595 | "metadata": {}, 596 | "output_type": "execute_result" 597 | } 598 | ], 599 | "source": [ 600 | "|3J¯4" 601 | ] 602 | }, 603 | { 604 | "cell_type": "markdown", 605 | "metadata": {}, 606 | "source": [ 607 | "Traditional mathematics also has a complicated and ill-defined order of evaluation. For example, is sine or multiplication evaluated first in sin *α φ*? How about in sin *α* cos *β*? And while functions that supposedly are on the same level evaluate from left to right, this doesn't apply to exponentiation, and how about *a* ÷ *bx*? APL has just one simple rule: All functions take *everything on their right* as right (or only) argument:" 608 | ] 609 | }, 610 | { 611 | "cell_type": "code", 612 | "execution_count": 25, 613 | "metadata": {}, 614 | "outputs": [ 615 | { 616 | "data": { 617 | "text/html": [ 618 | "7\n", 619 | "" 620 | ] 621 | }, 622 | "execution_count": 25, 623 | "metadata": {}, 624 | "output_type": "execute_result" 625 | } 626 | ], 627 | "source": [ 628 | "1+2×3" 629 | ] 630 | }, 631 | { 632 | "cell_type": "code", 633 | "execution_count": 26, 634 | "metadata": {}, 635 | "outputs": [ 636 | { 637 | "data": { 638 | "text/html": [ 639 | "8\n", 640 | "" 641 | ] 642 | }, 643 | "execution_count": 26, 644 | "metadata": {}, 645 | "output_type": "execute_result" 646 | } 647 | ], 648 | "source": [ 649 | "2×3+1" 650 | ] 651 | }, 652 | { 653 | "cell_type": "markdown", 654 | "metadata": {}, 655 | "source": [ 656 | "You may of course use parentheses to force order of evaluation:" 657 | ] 658 | }, 659 | { 660 | "cell_type": "code", 661 | "execution_count": 27, 662 | "metadata": {}, 663 | "outputs": [ 664 | { 665 | "data": { 666 | "text/html": [ 667 | "7\n", 668 | "" 669 | ] 670 | }, 671 | "execution_count": 27, 672 | "metadata": {}, 673 | "output_type": "execute_result" 674 | } 675 | ], 676 | "source": [ 677 | "(2×3)+1" 678 | ] 679 | }, 680 | { 681 | "cell_type": "markdown", 682 | "metadata": {}, 683 | "source": [ 684 | "These rules apply to **all** functions, whether built-in or user-defined. Know the syntax of one, and you know the syntax of all of them!" 685 | ] 686 | } 687 | ], 688 | "metadata": { 689 | "kernelspec": { 690 | "display_name": "Dyalog APL", 691 | "language": "apl", 692 | "name": "dyalog-kernel" 693 | }, 694 | "language_info": { 695 | "file_extension": ".apl", 696 | "mimetype": "text/apl", 697 | "name": "APL" 698 | }, 699 | "tryapl": { 700 | "category": "APL Basics", 701 | "description": "APL expressions and what they are made of", 702 | "name": "APL Expressions" 703 | } 704 | }, 705 | "nbformat": 4, 706 | "nbformat_minor": 2 707 | } 708 | -------------------------------------------------------------------------------- /Conway's Game of Life.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "In 1970, British mathematician John Horton Conway developed a cellular automaton known as [The Game of Life](http://en.wikipedia.org/wiki/Conway's_Game_of_Life). Dyalog's John Scholes put together a video exploration of an [APL implementation of the Game of Life](http://www.youtube.com/watch?v=a9xAKttWgP4&fmt=18).\n", 8 | "\n", 9 | "This tutorial steps through much the same path that John took in his presentation allowing you to investigate each individual step.\n", 10 | "\n", 11 | "First we'll build the initial board which is a 3 by 3 bit pattern centered in a 5 by 7 board." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 1, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "data": { 21 | "text/html": [ 22 | "1 2 3 4 5 6 7 8 9\n", 23 | "" 24 | ] 25 | }, 26 | "execution_count": 1, 27 | "metadata": {}, 28 | "output_type": "execute_result" 29 | } 30 | ], 31 | "source": [ 32 | "⍳ 9 ⍝ generate the first 9 integers" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "Many APL functions have mnemonic or visual clues to their meaning. In this case monadic (*monadic* means the function only has one argument) iota `⍳`, the Greek letter for \"i\", implements the **i**ndex generator function." 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "data": { 49 | "text/html": [ 50 | "1 2 3\n", 51 | "4 5 6\n", 52 | "7 8 9\n", 53 | "" 54 | ] 55 | }, 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "output_type": "execute_result" 59 | } 60 | ], 61 | "source": [ 62 | "3 3 ⍴ ⍳ 9" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "Dyadic (*dyadic* means the function has two arguments) rho `⍴` implements the **r**eshape function. As APL executes from right to left, `3 3 ⍴ ⍳ 9` reshapes `⍳ 9` into a 3 by 3 matrix." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 3, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "data": { 79 | "text/html": [ 80 | "0 1 1\n", 81 | "1 1 0\n", 82 | "0 1 0\n", 83 | "" 84 | ] 85 | }, 86 | "execution_count": 3, 87 | "metadata": {}, 88 | "output_type": "execute_result" 89 | } 90 | ], 91 | "source": [ 92 | "(3 3 ⍴ ⍳ 9) ∊ 2 3 4 5 8" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "Dyadic epsilon `∊` implements the \"**e**lement of\" function. This generates the starting bit pattern. Now we need to position it within our board. But first let's save the pattern in a variable named `r`" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 4, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "r ← (3 3 ⍴ ⍳ 9) ∊ 2 3 4 5 8" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "You can display `r` merely by entering its name." 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 5, 121 | "metadata": {}, 122 | "outputs": [ 123 | { 124 | "data": { 125 | "text/html": [ 126 | "0 1 1\n", 127 | "1 1 0\n", 128 | "0 1 0\n", 129 | "" 130 | ] 131 | }, 132 | "execution_count": 5, 133 | "metadata": {}, 134 | "output_type": "execute_result" 135 | } 136 | ], 137 | "source": [ 138 | "r" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "Now that we have our starting pattern, we'll center it in a 5 by 7 board. The first step is to use the take function `↑` to pad out the pattern to our desired size." 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 6, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "data": { 155 | "text/html": [ 156 | "0 1 1 0 0 0 0\n", 157 | "1 1 0 0 0 0 0\n", 158 | "0 1 0 0 0 0 0\n", 159 | "0 0 0 0 0 0 0\n", 160 | "0 0 0 0 0 0 0\n", 161 | "" 162 | ] 163 | }, 164 | "execution_count": 6, 165 | "metadata": {}, 166 | "output_type": "execute_result" 167 | } 168 | ], 169 | "source": [ 170 | "5 7 ↑ r" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "The next step is to column-center the pattern..." 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 7, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "data": { 187 | "text/html": [ 188 | "0 0 0 1 1 0 0\n", 189 | "0 0 1 1 0 0 0\n", 190 | "0 0 0 1 0 0 0\n", 191 | "0 0 0 0 0 0 0\n", 192 | "0 0 0 0 0 0 0\n", 193 | "" 194 | ] 195 | }, 196 | "execution_count": 7, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "¯2 ⌽ 5 7 ↑ r" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "The high minus `¯` is used to denote a negative number. The symbol `⌽` rotates along the last axis, which is the columns in an array of rank (*rank* is just another term for the number of dimensions an array has — a table is a rank 2 array) 2 greater.\n", 210 | "\n", 211 | "Next we row-center the pattern using the `⊖` function which rotates along the first axis." 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 8, 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "data": { 221 | "text/html": [ 222 | "0 0 0 0 0 0 0\n", 223 | "0 0 0 1 1 0 0\n", 224 | "0 0 1 1 0 0 0\n", 225 | "0 0 0 1 0 0 0\n", 226 | "0 0 0 0 0 0 0\n", 227 | "" 228 | ] 229 | }, 230 | "execution_count": 8, 231 | "metadata": {}, 232 | "output_type": "execute_result" 233 | } 234 | ], 235 | "source": [ 236 | "¯1 ⊖ ¯2 ⌽ 5 7 ↑ r" 237 | ] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": {}, 242 | "source": [ 243 | "We now assign the board to the variable `R`" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 9, 249 | "metadata": {}, 250 | "outputs": [], 251 | "source": [ 252 | "R ← ¯1 ⊖ ¯2 ⌽ 5 7 ↑ r" 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": {}, 258 | "source": [ 259 | "The rules for the Game of Life dictate which cells live based on their number of live neighbors. So, our next job is to count the neighbors and we'll do this by shifting the board by 1 unit in each direction and summing the result..." 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": 10, 265 | "metadata": {}, 266 | "outputs": [ 267 | { 268 | "data": { 269 | "text/html": [ 270 | "┌─────────────┬─────────────┬─────────────┐\n", 271 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 272 | "│0 0 1 1 0 0 0│0 0 0 1 1 0 0│0 0 0 0 1 1 0│\n", 273 | "│0 1 1 0 0 0 0│0 0 1 1 0 0 0│0 0 0 1 1 0 0│\n", 274 | "│0 0 1 0 0 0 0│0 0 0 1 0 0 0│0 0 0 0 1 0 0│\n", 275 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 276 | "└─────────────┴─────────────┴─────────────┘\n", 277 | "" 278 | ] 279 | }, 280 | "execution_count": 10, 281 | "metadata": {}, 282 | "output_type": "execute_result" 283 | } 284 | ], 285 | "source": [ 286 | "1 0 ¯1 ⌽¨ ⊂R" 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "metadata": {}, 292 | "source": [ 293 | "First, the enclose `⊂` function takes any array and turns it into a rank 0 array, also known as a scalar. Many APL functions support \"scalar extension\" which distributes the scalar and applies the function to each of the items in the other argument. In this case, we're using again to perform column shifts. The \"each\" operator (an *operator* takes function(s) as arguments and returns a new function) `¨` applies `⌽` between each element of the left argument `1 0 ¯1` and `⊂R`" 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": 11, 299 | "metadata": {}, 300 | "outputs": [ 301 | { 302 | "data": { 303 | "text/html": [ 304 | "┌─────────────┬─────────────┬─────────────┐\n", 305 | "│0 0 1 1 0 0 0│0 0 0 1 1 0 0│0 0 0 0 1 1 0│\n", 306 | "│0 1 1 0 0 0 0│0 0 1 1 0 0 0│0 0 0 1 1 0 0│\n", 307 | "│0 0 1 0 0 0 0│0 0 0 1 0 0 0│0 0 0 0 1 0 0│\n", 308 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 309 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 310 | "├─────────────┼─────────────┼─────────────┤\n", 311 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 312 | "│0 0 1 1 0 0 0│0 0 0 1 1 0 0│0 0 0 0 1 1 0│\n", 313 | "│0 1 1 0 0 0 0│0 0 1 1 0 0 0│0 0 0 1 1 0 0│\n", 314 | "│0 0 1 0 0 0 0│0 0 0 1 0 0 0│0 0 0 0 1 0 0│\n", 315 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 316 | "├─────────────┼─────────────┼─────────────┤\n", 317 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 318 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 319 | "│0 0 1 1 0 0 0│0 0 0 1 1 0 0│0 0 0 0 1 1 0│\n", 320 | "│0 1 1 0 0 0 0│0 0 1 1 0 0 0│0 0 0 1 1 0 0│\n", 321 | "│0 0 1 0 0 0 0│0 0 0 1 0 0 0│0 0 0 0 1 0 0│\n", 322 | "└─────────────┴─────────────┴─────────────┘\n", 323 | "" 324 | ] 325 | }, 326 | "execution_count": 11, 327 | "metadata": {}, 328 | "output_type": "execute_result" 329 | } 330 | ], 331 | "source": [ 332 | "1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂R" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": {}, 338 | "source": [ 339 | "Now we've used the outer product operator `∘.` which applies its function, in this case `⊖`, between all combinations of the left and right arguments. So, we wind up with a 3 by 3 array of with our original board in the center and all of the \"1-rotations\" surrounding.\n", 340 | "\n", 341 | "We can now add up the neighbors." 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": 12, 347 | "metadata": {}, 348 | "outputs": [ 349 | { 350 | "data": { 351 | "text/html": [ 352 | "┌─────────────┬─────────────┬─────────────┐\n", 353 | "│0 0 1 2 2 1 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 354 | "│0 1 2 2 1 0 0│0 0 1 2 2 1 0│0 0 0 0 0 0 0│\n", 355 | "│0 0 1 1 1 0 0│0 1 2 2 1 0 0│0 0 1 2 2 1 0│\n", 356 | "│0 0 0 0 0 0 0│0 0 1 1 1 0 0│0 1 2 2 1 0 0│\n", 357 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 1 1 1 0 0│\n", 358 | "└─────────────┴─────────────┴─────────────┘\n", 359 | "" 360 | ] 361 | }, 362 | "execution_count": 12, 363 | "metadata": {}, 364 | "output_type": "execute_result" 365 | } 366 | ], 367 | "source": [ 368 | "+/ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂R" 369 | ] 370 | }, 371 | { 372 | "cell_type": "markdown", 373 | "metadata": {}, 374 | "source": [ 375 | "`+/` sums along the last axis. `/` is another operator, called reduce, and applies its function along the last axis of its data. Notice that `/` \"reduces\" the rank of an array, in this case giving a result of a vector from a 3 by 3 matrix.\n", 376 | "\n", 377 | "Next we sum the vector..." 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "execution_count": 13, 383 | "metadata": {}, 384 | "outputs": [ 385 | { 386 | "data": { 387 | "text/html": [ 388 | "┌─────────────┐\n", 389 | "│0 0 1 2 2 1 0│\n", 390 | "│0 1 3 4 3 1 0│\n", 391 | "│0 1 4 5 4 1 0│\n", 392 | "│0 1 3 3 2 0 0│\n", 393 | "│0 0 1 1 1 0 0│\n", 394 | "└─────────────┘\n", 395 | "" 396 | ] 397 | }, 398 | "execution_count": 13, 399 | "metadata": {}, 400 | "output_type": "execute_result" 401 | } 402 | ], 403 | "source": [ 404 | "+/ +/ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂R" 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "metadata": {}, 410 | "source": [ 411 | "And this gives us a neighbor count of our original matrix.\n", 412 | "\n", 413 | "Now, a cell is \"live\" (has a 1) in the next generation if either its neighbor count is 3, or its neighbor count is 4 **and** the cell is alive in the current generation. So, we can find where the neighbor counts are 3 and 4..." 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 14, 419 | "metadata": {}, 420 | "outputs": [ 421 | { 422 | "data": { 423 | "text/html": [ 424 | "┌─────────────┬─────────────┐\n", 425 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 426 | "│0 0 1 0 1 0 0│0 0 0 1 0 0 0│\n", 427 | "│0 0 0 0 0 0 0│0 0 1 0 1 0 0│\n", 428 | "│0 0 1 1 0 0 0│0 0 0 0 0 0 0│\n", 429 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 430 | "└─────────────┴─────────────┘\n", 431 | "" 432 | ] 433 | }, 434 | "execution_count": 14, 435 | "metadata": {}, 436 | "output_type": "execute_result" 437 | } 438 | ], 439 | "source": [ 440 | "3 4 = +/ +/ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂R" 441 | ] 442 | }, 443 | { 444 | "cell_type": "markdown", 445 | "metadata": {}, 446 | "source": [ 447 | "And then take any 3, and 4's where there's a 1 in the current generation..." 448 | ] 449 | }, 450 | { 451 | "cell_type": "code", 452 | "execution_count": 15, 453 | "metadata": {}, 454 | "outputs": [ 455 | { 456 | "data": { 457 | "text/html": [ 458 | "┌─────────────┬─────────────┐\n", 459 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 460 | "│0 0 1 0 1 0 0│0 0 0 1 0 0 0│\n", 461 | "│0 0 0 0 0 0 0│0 0 1 0 0 0 0│\n", 462 | "│0 0 1 1 0 0 0│0 0 0 0 0 0 0│\n", 463 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 464 | "└─────────────┴─────────────┘\n", 465 | "" 466 | ] 467 | }, 468 | "execution_count": 15, 469 | "metadata": {}, 470 | "output_type": "execute_result" 471 | } 472 | ], 473 | "source": [ 474 | "1 R ∧ 3 4 = +/ +/ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂R" 475 | ] 476 | }, 477 | { 478 | "cell_type": "markdown", 479 | "metadata": {}, 480 | "source": [ 481 | "Since both of these matrices contribute to the next generation, we can use reduce again, this time using the `∨.∧` inner product and disclosing the result using `⊃` to make it a simple matrix." 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": 16, 487 | "metadata": {}, 488 | "outputs": [ 489 | { 490 | "data": { 491 | "text/html": [ 492 | "0 0 0 0 0 0 0\n", 493 | "0 0 1 1 1 0 0\n", 494 | "0 0 1 0 0 0 0\n", 495 | "0 0 1 1 0 0 0\n", 496 | "0 0 0 0 0 0 0\n", 497 | "" 498 | ] 499 | }, 500 | "execution_count": 16, 501 | "metadata": {}, 502 | "output_type": "execute_result" 503 | } 504 | ], 505 | "source": [ 506 | "⊃1 R ∨.∧ 3 4 = +/ +/ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂R" 507 | ] 508 | }, 509 | { 510 | "cell_type": "markdown", 511 | "metadata": {}, 512 | "source": [ 513 | "Now we've built an expression which produces the next generation for any boolean matrix `R`. Let's turn this into a function by enclosing it in curly braces `{` `}` and using the formal parameter `⍵<` in place of `R`. We'll call this function `life`." 514 | ] 515 | }, 516 | { 517 | "cell_type": "code", 518 | "execution_count": 17, 519 | "metadata": {}, 520 | "outputs": [ 521 | { 522 | "data": { 523 | "text/html": [ 524 | "┌─────────────┬─────────────┬─────────────┐\n", 525 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 1 0 0 0│\n", 526 | "│0 0 0 1 1 0 0│0 0 1 1 1 0 0│0 0 1 1 0 0 0│\n", 527 | "│0 0 1 1 0 0 0│0 0 1 0 0 0 0│0 1 0 0 1 0 0│\n", 528 | "│0 0 0 1 0 0 0│0 0 1 1 0 0 0│0 0 1 1 0 0 0│\n", 529 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 0 0 0 0 0│\n", 530 | "└─────────────┴─────────────┴─────────────┘\n", 531 | "" 532 | ] 533 | }, 534 | "execution_count": 17, 535 | "metadata": {}, 536 | "output_type": "execute_result" 537 | } 538 | ], 539 | "source": [ 540 | "life←{⊃1 ⍵ ∨.∧ 3 4 = +/ +/ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂⍵}\n", 541 | "R (life R) (life life R)" 542 | ] 543 | }, 544 | { 545 | "cell_type": "markdown", 546 | "metadata": {}, 547 | "source": [ 548 | "Displays the first 3 generations for `R`.\n", 549 | "\n", 550 | "Now, we can generalise that by writing a function `gen` which uses the power operator `⍣` to apply `life` to the power of the left argument to the right argument." 551 | ] 552 | }, 553 | { 554 | "cell_type": "code", 555 | "execution_count": 18, 556 | "metadata": {}, 557 | "outputs": [ 558 | { 559 | "data": { 560 | "text/html": [ 561 | "┌─────────────┬─────────────┬─────────────┬─────────────┐\n", 562 | "│0 0 0 0 0 0 0│0 0 0 1 0 0 0│0 0 1 1 0 0 0│0 1 0 0 0 0 0│\n", 563 | "│0 0 1 1 1 0 0│0 0 1 1 0 0 0│0 0 1 1 1 0 0│0 1 0 0 1 0 0│\n", 564 | "│0 0 1 0 0 0 0│0 1 0 0 1 0 0│0 1 0 0 1 0 0│0 1 0 0 1 0 0│\n", 565 | "│0 0 1 1 0 0 0│0 0 1 1 0 0 0│0 0 1 1 0 0 0│0 1 0 0 1 0 0│\n", 566 | "│0 0 0 0 0 0 0│0 0 0 0 0 0 0│0 0 1 1 0 0 0│0 1 0 0 1 0 0│\n", 567 | "└─────────────┴─────────────┴─────────────┴─────────────┘\n", 568 | "" 569 | ] 570 | }, 571 | "execution_count": 18, 572 | "metadata": {}, 573 | "output_type": "execute_result" 574 | } 575 | ], 576 | "source": [ 577 | "gen←{(life⍣⍵)⍺}\n", 578 | "R∘gen¨ ⍳4" 579 | ] 580 | }, 581 | { 582 | "cell_type": "markdown", 583 | "metadata": {}, 584 | "source": [ 585 | "Displays the next 4 generations for R by binding `R` with `gen` using `∘` and applying it with each of `⍳4`." 586 | ] 587 | } 588 | ], 589 | "metadata": { 590 | "kernelspec": { 591 | "display_name": "Dyalog APL", 592 | "language": "apl", 593 | "name": "dyalog-kernel" 594 | }, 595 | "language_info": { 596 | "file_extension": ".apl", 597 | "mimetype": "text/apl", 598 | "name": "APL" 599 | }, 600 | "tryapl": { 601 | "category": "Interesting Explorations", 602 | "description": "Implementing Conway's Game of Life", 603 | "name": "Conway's Game of Life" 604 | } 605 | }, 606 | "nbformat": 4, 607 | "nbformat_minor": 2 608 | } 609 | --------------------------------------------------------------------------------