-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathquestions.json
282 lines (282 loc) · 52.5 KB
/
questions.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
[
{
"topic": "A tour of Nix",
"path": "introduction/nix",
"question": "Welcome to 'A tour of Nix', a beautifully crafted introduction into the \n[Nix programming language](http://nixos.org/nix/manual/).\n\n\n**'A tour of Nix' focuses on programming language constructs and how \nNix can be algorithmically \nused to solve problems.** However, this is not an introduction into `nix-env`, \n`nix-shell`, `nix-repl` and \nwe won't build/install software using `stdenv.mkDerivation`. Still \nwe bundled [nixpkgs](https://github.com/nixos/nixpkgs) into \n'A tour of Nix' and you can use the **Nix library** functions' from \n**pkgs/lib**, which are used for packaging software.\n\nWhen ready, just click the next button on the top right corner.\n\n**Note:** [Youtube videos](https://www.youtube.com/watch?v=dKsA_yR7gQ4&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-)\n\n**Note: **Updated many questions in 2023!\n\n**Note:** 'A tour of Nix' can be used offline once it has loaded in the \nbrowser. \n##Shortcuts\n\n* next page: `ctrl + j`\n* prev page: `ctrl + k`\n* run : `shift + return`\n\n\n## Source\n\nThe **source code of 'A tour of Nix'** can be found here:\n<https://github.com/nixcloud/tour_of_nix>\n\nPlease see the **LICENSE** file in that repository for more details.\n\n\n## Authors\n\n* [Joachim Schiele] (mailto:[email protected])\n* [Paul Seitz] (mailto:[email protected])\n\nThanks to **contributors**:\n\n* [lassulus](https://github.com/lassulus) (debugging the questions, workflows)\n* [rashfael](https://github.com/rashfael) (design consulting)\n* [aflatter](https://github.com/aflatter) (helping with spinner design)\n* [goibhniu](https://github.com/cillianderoiste) (careful review)\n* [lethalman](http://lethalman.blogspot.de/) (careful review)\n\n**Note:** If we forgot to list you here, just let us know!\n\n## License(s)\n\n'A tour of Nix' contains this software:\n\n* [Nix 1.9](https://github.com/nixos/nix) (compiled with emscripten)\n* [nixpkgs](https://github.com/nixos/nixpkgs)\n* [emscripten-1.29.10](https://github.com/kripken/emscripten)\n* [codemirror 5.5](https://codemirror.net/)\n* [markdown.js](https://github.com/evilstreak/markdown-js)\n* [FileSaver.js](https://github.com/eligrey/FileSaver.js)\n\n\n### emscripten (1.29.10)\n-----\nEmscripten is available under 2 licenses, the MIT license and the\nUniversity of Illinois/NCSA Open Source License.\n\nBoth are permissive open source licenses, with little if any\npractical difference between them.\n\nThe reason for offering both is that (1) the MIT license is\nwell-known, while (2) the University of Illinois/NCSA Open Source\nLicense allows Emscripten's code to be integrated upstream into\nLLVM, which uses that license, should the opportunity arise.\n-----\n\n\n### Nix (1.9)\n\n---\n\nGNU LESSER GENERAL PUBLIC LICENSE\n\nVersion 2.1, February 1999\n\nCopyright (C) 1991, 1999 Free Software Foundation, Inc.\n51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\nEveryone is permitted to copy and distribute verbatim copies\nof this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL. It also counts\nas the successor of the GNU Library Public License, version 2, hence\nthe version number 2.1.]\n\n[full details](https://github.com/NixOS/nix/blob/master/COPYING)\n\n---\n\n### nixPkgs\n\n-----\n\nCopyright (c) 2003-2006 Eelco Dolstra\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-----\n\nNote: the license above does not apply to the packages built by the\nNix Packages collection, merely to the package descriptions (i.e., Nix\nexpressions, build scripts, etc.). Also, the license does not apply\nto some of the binaries used for bootstrapping Nixpkgs (e.g.,\npkgs/stdenv/linux/tools/bash). It also might not apply to patches\nincluded in Nixpkgs, which may be derivative works of the packages to\nwhich they apply. The aforementioned artifacts are all covered by the\nlicenses of the respective packages.\n\n-----\n\n### codemirror (5.5)\n---\n\nCopyright (C) 2015 by Marijn Haverbeke <[email protected]> and others\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n---\n\n### markdown.js\n\n---\n\nReleased under the MIT license.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of \nthis software and associated documentation files (the \"Software\"), to deal in the \nSoftware without restriction, including without limitation the rights to use, copy, \nmodify, merge, publish, distribute, sublicense, and/or sell copies of the Software, \nand to permit persons to whom the Software is furnished to do so, subject to the \nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included in all \ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN \nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n---\n\n### FileSaver.js\n\n---\n\nCopyright © 2015 [Eli Grey][1].\n\nPermission is hereby granted, free of charge, to any person obtaining a \ncopy of this software and associated documentation files (the \"Software\"), \nto deal in the Software without restriction, including without limitation \nthe rights to use, copy, modify, merge, publish, distribute, sublicense, \nand/or sell copies of the Software, and to permit persons to whom the \nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included \nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, \nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS \nOR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN \nAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH \nTHE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n [1]: http://eligrey.com\n\n---",
"code": "{\n helloWorld = \"Hello\" + \" \" + \"World\";\n}\n",
"solution": "#you found the solution button, please don't cheat yourself!\n{\n helloWorld = \"Hello\" + \" \" + \"World\";\n}\n",
"youtube": "https://www.youtube.com/watch?v=dKsA_yR7gQ4&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "How it works...",
"path": "introduction-tour",
"question": "## Usability\n1. You read the description/text on the `right pane`\n (That is what you are doing right now).\n\n2. You write/fix code on the `left pane`:\n\n * First thing, **complete v on the left, like:**\n \n v = \"understood\";\n \n * Click `run` and if the grey 'output-box' turns \n \n * **green**\n \n Everything is good! Change **v** to something else and hit `run` again!\n \n * **red**\n \n You have to fix something! If you can't think of what\n we want from you, then, and only then, click the `solution`\n button and adapt your solution.\n \n3. Finally there is the `reset` button. If you screwed the code,\n just hit `reset`. \n \n **Note:** Using `reset` you will lose the text you had\n there before.\n\n## The shell\n\nWhenever you hit `run`, this happens:\n\n1. javascript writes `the editor's` contents into the file `/test.nix`\n\n2. then it runs `nix-instantiate.js` with:\n\n -I nixpkgs=nixpkgs/ --eval --strict --show-trace /test.nix\n\n**Note:** If you've got **Nix** or **NixOS** installed natively, then you \ncan also execute this examples on the shell.\n\n## Privacy\n\nWe are:\n* not using **cookies** and \n* **we don't store your results.**\n\nHappy hacking & learning!\n\n**Note:** If you hit `reload` in your browser, everything is gone!\n\n\n\n",
"code": "# code goes here\n{\n v=\"\";\n}\n",
"solution": "{ v=\"understood\"; }",
"youtube": "https://www.youtube.com/watch?v=pnzucIAFXn0&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Hello World",
"path": "introduction/helloworld",
"question": "A simple introduction to `Strings` in Nix:\n\n* Complete the `String` to \"Hello World\", replace all 'X' with \nattributes or `Strings`.\n\n## Let expressions\n\nThe let expression is composed of:\n\n let <bindings> in <body>\n \nThe bindings are a series of definitions separated by semi-colons. \n\n**Note:** In Nix you can use the `let`-construct to bind a `value` to a \n`attribute` but also a `function`. In the `<body>` you can then\nrefer to the `bound values`, even multiple times.\n\nMore at [Nix by example part1](https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55#8310) by James Fisher.\n",
"code": "let \n h = \"Hello\";\n w = \"World\";\nin\n{\n helloWorld = h + X + X;\n}\n",
"solution": "let \n h = \"Hello\";\n w = \"World\";\nin\n{\n helloWorld = h + \" \" + w;\n}\n",
"youtube": "https://www.youtube.com/watch?v=p0ZB03Br3lM&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Strings",
"path": "strings/introduction",
"question": "Nix can also insert `Strings` with `${attribute}` where `attribute` is referenced from a let scope.\n \n * Complete ex0, ex1 and ex2 to each print 'Hello World'.",
"code": "let \n h = \"Hello\";\nin\n{\n ex0 = \"${h} X\";\n ex1 = \"${h + X + X}\";\n ex2 = ''${h + X + X}'';\n}\n",
"solution": "let \n h = \"Hello\";\nin\n{\n ex0 = \"${h} World\";\n ex1 = \"${h + \" \" + \"World\"}\";\n ex2 = ''${h + \" \" + \"World\"}'';\n}\n",
"youtube": "https://www.youtube.com/watch?v=DX97PJpQLbI&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Multiline string",
"path": "strings/multiline",
"question": "In Nix you are frequently using multiline `strings` to create text files using two quotes, i.e. `''xxx''` in combination with attributes:\n\n foo = ''\n foo: ${fooValue}\n bar: ${barValue}\n '';\n\nRead <https://nixos.org/manual/nix/stable/language/values> about string handling in Nix!\n\nSo now:\n\n * Format ex0 as wanted by the solution checker!\n\n**Note:** Play a little with the space indention depth and see what change it imposes on the generated string.\n\n**Note:** If `vip` is `false`, we get an empty newline with indention! We could also append the vipString to ex0 like `ex0 = ''...'' + vipString` and rewrite vipString with `\"` instead of `''`to fix this as `\"` won't remove our leading spaces.",
"code": "let \n user = \"mrNix\";\n pass = \"99supersecret\";\n vip = true;\n vipString = if vip == true then ''vip: XXX '' else XXX\nin\n{\n ex0 = ''\n ${user}\n password: XXX\n ${vipString}\n '';\n}\n",
"solution": "let \n user = \"mrNix\";\n pass = \"99supersecret\";\n vip = true;\n vipString = if vip == true then ''vip: \"true\" '' else \"\";\nin\n{\n ex0 = ''\n ${user}\n password: ${pass}\n ${vipString}\n '';\n}\n",
"youtube": "https://www.youtube.com/watch?v=DiuMuzxOqtM&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Integer to string",
"path": "strings/typeconversion",
"question": "Inserting `Strings` using the pattern `${attribute}` works great \nwith `Strings`. But `${}` can do more. You can even run functions within it.\n\nUse this and the builtin function `toString` to make the code work.\n\n**Note:** See also <https://noogle.dev/>\n\n**Note:** More builtin functions can be found in the [Nix manual](https://nixos.org/manual/nix/stable/expressions/builtins.html#built-in-functions).\n",
"code": "let \n h = \"Strings\";\n v = 4;\nin\n{\n helloWorld = \"${h} ${v} the win!\";\n}\n",
"solution": "let \n h = \"Strings\";\n v = 4;\nin\n{\n helloWorld = \"${h} ${toString v} the win!\";\n}\n",
"youtube": "https://www.youtube.com/watch?v=fyhPbWVCv_g&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Functions: Introduction",
"path": "functions/introduction",
"question": "Next we will have a look into `functions` and how they are defined and called. Don't forget to to use spaces between the arguments of the functions you write!\n\n Now:\n\n* Write a `function` that consumes 3 `Strings` and combines them to one. \n\n**Note:** Strings concatenation can be done with the '+' operator.\n\n**Note:** Read about writing functions in <https://nixos.org/manual/nix/stable/language/constructs#functions>\n\n**Note:** There are builtin functions you can always use, see <https://nixos.org/manual/nix/stable/language/builtins>",
"code": "let\n f = \"f\";\n o = \"o\";\n func = a: b: c: XXX; \nin\n{\n foo = func f o \"o\";\n}\n",
"solution": "let\n f = \"f\";\n o = \"o\";\n func = a: b: c: a+b+c; \nin\n{\n foo = func f o \"o\";\n}\n",
"youtube": "https://www.youtube.com/watch?v=rKWJFfBr7cg&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Functions: Your first function!",
"path": "functions/minmax",
"question": "What to do:\n\n* Implement the `min` and the `max` function using `if () then X else Y`\n\n**Note:** those functions already exist and can be accessed with `lib.min` \nand `lib.max` (don't use lib.min and lib.max here but instead implement them yourself in this exercise).\n \n**Experiments:** \n\n* What happens if you create an infinite recursion call to `min`?\n* Now, instead of calling your `min` and `max` implementation, use `lib.min` and\n`lib.max`. \n\n The question is actually: what has to be added in order to use `lib`?\n* Finally, compare: min/max with these arguments: 9 and -1, how to make negative numbers work? \n \n ",
"code": "let\n min = XX #modify these\n max = XX #two lines only\nin\n{\n ex0 = min 5 3;\n ex1 = max 9 4;\n}\n",
"solution": "let\n min = x: y: if x < y then x else y;\n max = x: y: if x > y then x else y;\nin\n{\n ex0 = min 5 3;\n ex1 = max 9 4;\n}\n# make stdenv.lib available\n# with import <nixpkgs> { };\n# {\n# # finally make use of it\n# ex0 = stdenv.lib.min 9 (-1);\n# ex1 = stdenv.lib.max 9 (-1);\n# }\n# you need to use () precedence to not compute (9 -1) algebraic expression instead.",
"youtube": "https://www.youtube.com/watch?v=XD5si5Tz8QU&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Functions: attribute sets arguments",
"path": "functions/attrsets",
"question": "When passing an `attribute set` to `function`, you can set default values.\n\nDoing so, allows the function to be called without that parameter, making \nit optional.\n\n**Note:** A default value is defined with a '?'. \n\nNow:\n\n* Change the `function` 'func' in a way that **foobar** is \nevaluated to **'foobar'**.\n\n",
"code": "let\n f = \"f\";\n o = \"o\";\n b = \"b\";\n func = {a ? f, b , c }: a+b+c; #only modify this line!\nin\nrec {\n foo = func {b=\"o\"; c=o;}; #must evaluate to \"foo\"\n bar = func {a=b; c=\"r\";}; #must evaluate to \"bar\"\n foobar = func {a=foo;b=bar;}; #must evaluate to \"foobar\"\n}\n",
"solution": "let\n f = \"f\";\n o = \"o\";\n b = \"b\";\n func = {a ? f, b ? \"a\", c ? \"\"}: a+b+c; #Only modify this line! \nin\nrec {\n foo = func {b=\"o\"; c=o;}; #should be foo\n bar = func {a=b; c=\"r\";}; #should be bar\n foobar = func {a=foo;b=bar;}; #should be foobar\n}",
"youtube": "https://www.youtube.com/watch?v=4Cfk41ylC2E&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Functions: the @-pattern",
"path": "functions/ellipsis",
"question": "## Ellipsis\n\nFunctions can be called with an `attribute set`, as we have seen.\nThis `attribute set` must contain all required 'function \narguments`.\n\nHowever, such an `Attribute set` can contain additional attributes but\nyou have to add `...` like this:\n\n func2 = args@{a, b, c, ...}: a+b+c+args.d;\n\n**Note:** `...` is called `ellipsis`.\n\n## @-pattern\n\nInside a function, those `attributes` can be accessed with the \n`@-pattern`.\n\nNow complete the arguments `attribute set`:\n\n * **foo** must evaluate to 'foo'\n * **foobar** must evaluate to 'foobar'\n\n",
"code": "let\n arguments = {a=\"f\"; b=\"o\"; c=X; d=X;}; #only modify this line\n func = {a, b, c, ...}: a+b+c; \n func2 = args@{a, b, c, ...}: a+b+c+args.d;\nin\n{\n #the argument d is not used \n foo = func arguments;\n #now the argument d is used\n foobar = func2 arguments;\n}\n",
"solution": "let\n arguments = {a=\"f\"; b=\"o\"; c=\"o\"; d=\"bar\";}; #only modify this line\n\n func = {a, b, c, ...}: a+b+c; \n func2 = args@{a, b, c, ...}: a+b+c+args.d;\nin\n{\n #the argument d is not used \n foo = func arguments;\n #now the argument d is used\n foobar = func2 arguments;\n}\n",
"youtube": "https://www.youtube.com/watch?v=4HE5hx8E_QA&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Functions: the @-pattern II",
"path": "functions/ellipsis2",
"question": "`Attribute sets` can contain additional attributes which are not part of \nthe function definition.\n\nInside a function, those `attributes` can be accessed with the \n`@-pattern`.\n\n**Note:** `bargs@{a, b, ...}:` is equivalent to `{a, b, ...}@bargs:`.\n\nNow complete the last line: \n\n* It should evaluate to 'foobar'\n\nSee usage in [nixpkgs/all-packages](https://github.com/NixOS/nixpkgs/blob/5a237aecb57296f67276ac9ab296a41c23981f56/pkgs/top-level/all-packages.nix#L16761).\n",
"code": "let\n func = {a, b, ...}@bargs: if a == \"foo\" then\n b + bargs.c else b + bargs.x + bargs.y;\nin\n{\n #complete next line so it evaluates to \"foobar\"\n foobar = func {a=\"bar\"; XXX #ONLY EDIT THIS LINE\n}\n",
"solution": "let\n func = {a, b, ...}@bargs: if a == \"foo\" then\n b + bargs.c else b + bargs.x + bargs.y;\nin\n{\n #complete next line so it evaluates to \"foobar\"\n foobar = func {a=\"bar\"; b=\"foo\"; x=\"bar\"; y=\"\";}; \n}\n",
"youtube": "https://www.youtube.com/watch?v=Rwcwcw169P8&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Partial application",
"path": "functions/partial_application",
"question": "**Partial application**: A function returning another function that might return another function, but each returned function can take several parameters.\n\nLet's have a look into `functions` and how they are defined and called:\n\n* solve each question: `ex00, ex01, ...` by only modifying X with a \n`value` of type `Int`\n\n**Note:** If you see `ex03 = <LAMBDA>;` after `run`, this means \nthat `ex03` is bound to a `function`.\n",
"code": "let\n b = 1;\n fu0 = (x: x);\n fu1 = (x: y: x + y) 4;\n fu2 = (x: y: (2 * x) + y);\nin\nrec {\n ex00 = fu0 X; # must return 4\n# ex01 = (fu1) X; # must return 5\n# ex02 = (fu2 X ) X; # must return 7\n# ex03 = (fu2 X ); # must return <LAMBDA>s\n# ex04 = ex03 X; # must return 7\n# ex05 = (n: x: (fu2 x n)) X X; # must return 7\n}\n",
"solution": "let\n b = 1;\n fu0 = (x: x);\n fu1 = (x: y: x + y) 4;\n fu2 = (x: y: (2 * x) + y);\nin\nrec {\n ex00 = fu0 4; # must return 4\n ex01 = (fu1) 1; # must return 5\n ex02 = (fu2 2) 3; # must return 7\n ex03 = (fu2 3); # must return <LAMBDA>\n ex04 = ex03 1; # must return 7\n ex05 = (n: x: (fu2 x n)) 3 2; # must return 7\n}\n",
"youtube": "https://www.youtube.com/watch?v=ITaAmTWGQeE&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Partial application II",
"path": "functions/partial_application2",
"question": "Functions can be called with an `attribute set`, as we have seen. This is another common \nexample of partial application, so solve it!\n\nComplete the arguments `attribute set`:\n\n * A must evaluate to 'HappyFunctionsAreCalled'\n\n",
"code": "let\n arguments = {a=\"Happy\"; b=\"Awesome\";};\n\n func = {a, b}: {d, b, c}: a+b+c+d;\nin\n{\n A = func arguments XXX #only modify this line\n}\n",
"solution": "let\n arguments = {a=\"Happy\"; b=\"Awesome\";};\n\n func = {a, b}: {d, b, c}: a+b+c+d;\nin\n{\n A = func arguments {d=\"Called\"; b = \"Functions\"; c=\"Are\";};\n}\n",
"youtube": "https://www.youtube.com/watch?v=WaiIcgidSgs&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Attribute sets: rec",
"path": "attrset/rec",
"question": "`Sets` or `attribute sets` are really **the core of the Nix language**, since ultimately the language \nis all about creating derivations, which are really \njust `sets of attributes` to be passed to build scripts.\n\nSets are just a list of name/value pairs (called attributes) \nenclosed in curly brackets, where each value is an arbitrary \nexpression terminated by a semicolon. For example:\n\n { x = 123;\n text = \"Hello\";\n y = f { bla = 456; };\n }\n\nThis defines a set with attributes named x, text, y. The order of the attributes is irrelevant. An attribute name may only occur once.\n\nNow:\n\n* Find out what the `rec` keyword does and what the difference to an `attribute set` without `rec` is.\n* Delete the `rec` before the `attribute set` and observe the different behaviour of the nix interpreter.\n\n**Hint:** You find the answer within the solution section.\n\n**Note:** That is all for now, but you can continue reading in the [nix documentation](https://nixos.org/manual/nix/stable/language/constructs.html#recursive-sets).\n\n",
"code": "rec {\n x = \"a\";\n y = x;\n}\n",
"solution": "rec {\n x = \"a\";\n y = x;\n}\n#Recursive sets are just normal sets, but the attributes can refer to each other.\n#Be aware of infinite recursions. They are not possible!\n#rec {\n# x = y;\n# y = x;\n#} Does not Work.",
"youtube": "https://www.youtube.com/watch?v=dc79E_EC-E8&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Attribute sets: examples 1",
"path": "attrset/examples",
"question": " Make all `ex0` up to `ex7` evaluate to true.\n\n**Note:** For the '?' operator, see <https://nixos.org/manual/nix/stable/language/operators#has-attribute>\n\n**Note:** <https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs>",
"code": "with import <nixpkgs> { };\nwith stdenv.lib;\nlet\n attr = {a=\"a\"; b = 1; c = true;};\n s = \"b\";\nin\n{\n #replace all X, everything should evaluate to true\n ex0 = isAttrs X;\n# ex1 = attr.a == X;\n# ex2 = attr.${s} == X;\n# ex3 = attrVals [\"c\" \"b\"] attr == [ XXX ];\n# ex4 = attrValues attr == [ XXX ];\n# ex5 = builtins.intersectAttrs attr {a=\"b\"; d=234; c=\"\";} \n# == { X = X; X = X;};\n# ex6 = removeAttrs attr [\"b\" \"c\"] == { XXX };\n# ex7 = ! attr ? a == XXX;\n}\n",
"solution": "with import <nixpkgs> { };\nwith stdenv.lib;\nlet\n attr = {a=\"a\"; b = 1; c = true;};\n s = \"b\";\nin\n{\n #replace all X, everything should evaluate to true\n ex0 = isAttrs attr;\n ex1 = attr.a == \"a\";\n ex2 = attr.${s} == 1;\n ex3 = attrVals [\"c\" \"b\"] attr == [true 1];\n ex4 = attrValues attr == [\"a\" 1 true];\n ex5 = builtins.intersectAttrs attr {a=\"b\"; d=234; c=\"\";} == { a = \"b\"; c=\"\";};\n ex6 = removeAttrs attr [\"b\" \"c\"] == {a = \"a\";};\n ex7 = ! attr ? a == false;\n}\n",
"youtube": "https://www.youtube.com/watch?v=GQO1HUV0A9E&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Attribute sets: examples 2",
"path": "attrset/examples2",
"question": " Make `ex0` and `ex1` evaluate to true.",
"code": "let\n list = [ { name = \"foo\"; value = 123; }\n { name = \"bar\"; value = 456; } ];\n string = ''{\"x\": [1, 2, 3], \"y\": null}'';\nin \n{\n ex0 = builtins.listToAttrs list == { XXX };\n ex1 = builtins.fromJSON string == { XXX };\n}\n",
"solution": "let\n list = [ { name = \"foo\"; value = 123; }\n { name = \"bar\"; value = 456; } ];\n string = ''{\"x\": [1, 2, 3], \"y\": null}'';\nin \n{\n ex0 = builtins.listToAttrs list == {foo = 123; bar = 456;};\n ex1 = builtins.fromJSON string == {x = [1 2 3]; y = null;};\n}\n\n\n",
"youtube": "https://www.youtube.com/watch?v=GQO1HUV0A9E&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Attribute sets: examples 3",
"path": "attrset/examples3",
"question": "To learn the basic syntax replace every XX in the `rec scope` with \nvalues from the `let scope`.\n\nNow:\n\n* Exercise should evaluate to true.",
"code": "let\n attrSetBonus = {f = {add = (x: y: x + y);\n mul = (x: y: x * y);};\n n = {one = 1; two = 2;};};\nin\nrec {\n #Bonus: use only the attrSetBonus to solve this one\n exBonus = 5 == XX ( XX XX XX ) XX;\n}\n",
"solution": "let\n attrSetBonus = {f = {add = (x: y: x + y);\n mul = (x: y: x * y);};\n n = {one = 1; two = 2;};};\nin\nrec {\n #Bonus: use only the attrSetBonus to solve this one\n exBonus = with attrSetBonus; 5 == f.add (f.mul n.two n.two) n.one ;\n}",
"youtube": "https://www.youtube.com/watch?v=IbRyAUZ7aKw&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Attribute sets: merging",
"path": "attrset/merging",
"question": "Since programming in Nix is all about `attribute sets` it is important\nto know how to `merge` these using the `//` operator.\n\n l = {a=\"A\"; b=\"B\";} // {a=\"aaa\"};\n\nwill evaluate to:\n\n l = {a=\"aaa\"; b=\"B\";};\n \nas the later `set` overwrites the attributes from the earlier one.\n\nNow:\n\n* Every exercise `ex00, ex01, ...` should evaluate to what it is compared \nto, just see the output after hitting 'run' once.\n\n",
"code": "let\n x = { a=\"bananas\"; b= \"pineapples\"; };\n y = { a=\"kakis\"; c =\"grapes\"; };\n z = { a=\"raspberrys\"; c= \"oranges\"; };\n\n func = {a, b, c ? \"another secret ingredient\"}: \"A drink with: \" + \n a + \", \" + b + \" and \" + c;\nin\nrec {\n ex00=func ( x ); \n # hit 'run', you need the output to solve this!\n #ex01=func (y // X ); \n #ex02=func (x // { X=\"lychees\";});\n #ex03=func (X // x // z);\n}\n\n",
"solution": "with import <nixpkgs> { };\nlet\n x = { a=\"bananas\"; b= \"pineapples\"; };\n y = { a=\"kakis\"; c =\"grapes\"; };\n z = { a=\"raspberrys\"; c= \"oranges\"; };\n\n func = {a, b, c ? \"another secret ingredient\"}: \"A drink with: \" + \n a + \", \" + b + \" and \" + c;\nin\nrec {\n ex00=func (x); \n ex01=func (y // x ); \n ex02=func (x // { c=\"lychees\";});\n ex03=func (z // x // z);\n}\n",
"youtube": "https://www.youtube.com/watch?v=55HXT8Xxh1Q&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Attribute sets and booleans",
"path": "attrset/booleans",
"question": "To learn the basic syntax of Nix, replace every XX in the function body\nwith values from the attribute `attrSet` bound in the let scope.\n\nEach individual exercise `ex00, ex01, ...` should evaluate to `true`. \n\n**Note:** Remove the `#` to uncomment the exercises as you proceed.\n\nSee [Nix documentation](https://nixos.org/manual/nix/stable/language/values#attribute-set) \nfor more details on `attribute sets`.\n\n",
"code": "let\n attrSet = {x = \"a\"; y = \"b\"; b = {t = true; f = false;};};\n attrSet.c = 1;\n attrSet.d = null;\n attrSet.e.f = \"g\";\nin\nrec {\n #boolean\n ex0 = attrSet.b.t;\n #equal\n# ex01 = \"a\" == attrSet.XX; \n #unequal \n# ex02 = !(\"b\" != attrSet.XX );\n #and/or/neg\n# ex03 = ex01 && !ex02 || ! attrSet.XX;\n #implication\n# ex04 = true -> attrSet.XX;\n# ex05 = attrSet.XX ? e;\n}\n",
"solution": "let\n attrSet = {x = \"a\"; y = \"b\"; b = {t = true; f = false;};};\n attrSet.c = 1;\n attrSet.d = null;\n attrSet.e.f = \"g\";\nin\nrec {\n ex0 = attrSet.b.t;\n #equal\n ex01 = \"a\" == attrSet.x;\n #unequal \n ex02 = !(\"b\" != attrSet.y);\n #and/or/neg\n ex03 = ex01 && !ex02 || !attrSet.b.f;\n #implication\n ex04 = true -> attrSet.b.t;\n #contains attribute\n ex05 = attrSet ? e;\n}",
"youtube": "https://www.youtube.com/watch?v=BZACbPJg9Oo&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Lists",
"path": "lists/operations",
"question": "To learn the basic syntax replace every XX in the function body with values from the let scope.\n\nDo this:\n\n * Every exercise should evaluate to true.",
"code": "with import <nixpkgs> { };\nwith stdenv.lib;\nlet\n list = [2 \"4\" true false {a = 27;} false 3];\n f = x: isString x;\n s = \"foobar\";\nin\n{\n #replace all X, everything should evaluate to true\n ex00 = isList X;\n# ex01 = elemAt list 2 == X;\n# ex02 = length list == X;\n# ex03 = last list == X;\n# ex04 = filter f list == [ XX ];\n# ex05 = head list == X;\n# ex06 = tail list == [ XXX ];\n# ex07 = remove true list == [ XXX ];\n# ex08 = toList s == [ XXX ];\n# ex09 = take 3 list == [ XXX ];\n# ex10 = drop 4 list == [ XXX ];\n# ex11 = unique list == [ XXX ];\n# ex12 = list ++ [\"x\" \"y\"] == [ XXX ];\n}\n",
"solution": "with import <nixpkgs> { };\nwith stdenv.lib;\nlet\n list = [2 \"4\" true false {a = 27;} false 3];\n f = x: isString x;\n s = \"foobar\";\nin\n{\n #replace all X, everything should evaluate to true\n ex00 = isList list;\n ex01 = elemAt list 2 == true;\n ex02 = length list == 7;\n ex03 = last list == 3;\n ex04 = filter f list == [\"4\"];\n ex05 = head list == 2;\n ex06 = tail list == [\"4\" true false {a = 27;} false 3];\n ex07 = remove true list == [2 \"4\" false {a = 27;} false 3];\n ex08 = toList s == [s];\n ex09 = take 3 list == [2 \"4\" true];\n ex10 = drop 4 list == [{a = 27;} false 3];\n ex11 = unique list == [2 \"4\" true false {a = 27;} 3];\n ex12 = list ++ [\"x\" \"y\"] == [2 \"4\" true false {a = 27;} false 3 \"x\" \"y\"];\n}\n",
"youtube": "https://www.youtube.com/watch?v=yUfMxGs1AZQ&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Lists & attribute sets",
"path": "lists/examples1",
"question": "To learn the basic syntax replace every XX in the function body with values from the let scope.\n\n\nEvery exercise should evaluate to true.",
"code": "let\n attrSet = {x = \"a\"; y = \"b\"; b = {t = true; f = false;};};\n attrSet.c = 1;\n attrSet.d = 2;\n attrSet.e.f = \"g\";\n\n list1 = [attrSet.c attrSet.d];\n list2 = [attrSet.x attrSet.y];\n\nin\n{\n #List concatenation.\n ex0 = [\"a\" \"b\" 1 2] == XX ++ XX;\n}\n",
"solution": "let\n attrSet = {x = \"a\"; y = \"b\"; b = {t = true; f = false;};};\n attrSet.c = 1;\n attrSet.d = 2;\n attrSet.e.f = \"g\";\n\n list1 = [attrSet.c attrSet.d];\n list2 = [attrSet.x attrSet.y];\n\nin\n{\n #List concatenation.\n ex0 = [\"a\" \"b\" 1 2] == list2 ++ list1;\n}",
"youtube": "https://www.youtube.com/watch?v=Qg4tM_ebCoU&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "inherit/import/with!",
"path": "library/usage",
"question": "These 3 keywords can be confused pretty easily. Since we are using them\na lot in `A tour of Nix` we need to introduce them properly.\n\n## With\n\nA with-expression, introduces the `set e1` into the lexical scope of the `expression e2`. \n\n let \n as = { x = \"foo\"; y = \"bar\"; };\n in \n with as; x + y\n\n## Import\n\nLoad, parse and return the Nix expression in the file path. \n`import` implements Nix’s module system: you can put any Nix expression (such as a set or a function) in a separate file, and use it from Nix expressions in other files.\n\n rec {\n x = 123;\n y = import ./foo.nix;\n }\n\n## Inherit\nThe `inherit` keyword causes the specified `attributes` to be bound to whatever \nattributes with the same name happen to be in scope.\n\n let \n x = 123; \n in\n { \n inherit x;\n y = 456;\n }\n`inherit` takes one or more arguments.\n\nDo this:\n\n* make it work!",
"code": "let \n myImport = import <nixpkgs> {};\n x = 123; \n as = { a = \"foo\"; b = \"bar\"; };\n \nin with as; { \n inherit x; #example\n #fix line below: we want a and b in this scope\n inherit X; \n #also fix this line\n z = XXX.lib.isBool true;\n}\n",
"solution": "let \n myImport = import <nixpkgs> {};\n x = 123; \n as = { a = \"foo\"; b = \"bar\"; };\n \nin with as; { \n inherit x;\n inherit a b;\n z = myImport.lib.isBool true;\n}\n",
"youtube": "https://www.youtube.com/watch?v=1XwNjrCVUvs&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Scoping of attributes in let/with",
"path": "scopes",
"question": "This question is about scopes. `let` binds `attributes` as well as `with` does.\n\nQuestion: Which value is `res` assinged to and why?\n\nSolution: See the `solution` button's associated source code.\n\n",
"code": "let\n x = 123;\n as = { a = \"foo\"; b = \"bar\"; x=\"234\"; };\n \nin with as; {\n res = x; # what value is res bound to?\n}\n\n",
"solution": "{ res = 123; }\n# most ppl would assume that x would be bound to \"234\" because it was\n# introduced last using `with as` but instead it actualy binds to 123;\n#\n#See this example, why it makes sense:\n#{ config, lib, pkgs, ... }:\n#\n#let\n# vim = pkgs.stdenv.mkDerivation { \n# name = \"vim-hack\";\n# unpackPhase = \"true\"; \n# installPhase = ''\n# mkdir -p $out/bin; \n# echo '#!/bin/sh\n# echo hi' > $out/bin/vim1; \n# chmod u+x $out/bin/vim1\n# '';\n# };\n#in\n#\n#{\n# environment.systemPackages = with pkgs; [ vim ];\n#}\n",
"youtube": "https://www.youtube.com/watch?v=LPU7-hIGQQ0&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Typing system",
"path": "types",
"question": "The Nix language uses dynamic typing and there are `builtin` \nfunctions to check the type of a `binding`. \n\n**Note:** use these functions: `isBool`, \n`isInt`, \n`isString`, \n`isNull`, \n`isList`, \n`isAttrs` and \n`isFunction`.\n\nDo this:\n\n* go through `ex00, ex01, ...` and replace X by `isBool` in respect to the\n `type`\n* fix `ex04`, what is the problem?\n\n**Note:** `()` can either be a `function` or indicates `precedence`.\n\n See also <https://nixos.org/manual/nix/stable/language/values>.",
"code": "with import <nixpkgs> {};\nwith lib;\n{\n ex00 = isAttrs {};\n #ex01 = isX \"a\"; \n #ex02 = isX (-3); \n #ex03 = isX (x: x);\n #ex04 = isX (x:x);\n #ex05 = isX (\"x\");\n #ex06 = isX null; \n #ex07 = isX (y: y+1);\n #ex08 = isX [({z}: z) (x: x)];\n #ex09 = isX {a=[];};\n #ex10 = isX -10; # oh, what is that?\n}\n",
"solution": "with import <nixpkgs> {};\nwith lib;\n{\n ex00 = isAttrs {};\n ex01 = isString \"a\"; \n ex02 = isInt (-3); \n ex03 = isFunction (x: x);\n ex04 = isString (x:x); # this is because of url parsing: foo = http://bar.com;\n ex05 = isString (\"x\");\n ex06 = isNull null; \n ex07 = isFunction (y: y+1);\n ex08 = isList [({z}: z) (x: x)];\n ex09 = isAttrs {a=[];};\n ex10 = isInt (-10); # () were missing\n}",
"youtube": "https://www.youtube.com/watch?v=EsbiR4uwywo&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Assertions",
"path": "assertions",
"question": "`Assertions` are generally used to check that certain requirements \non or between features and dependencies hold. They look like this:\n\n assert e1; e2\n \nwhere `e1` is an expression that should evaluate to a `boolean` value. \nIf it evaluates to `true`, `e2` is returned; otherwise expression \nevaluation is aborted and a backtrace is printed.\n\n**Note:** that **->** is the **logical implication** Boolean operation.\n\n See also <https://nixos.org/manual/nix/stable/language/constructs#assertions>.",
"code": "with import <nixpkgs> {};\nlet\n func = x: y: assert (x==2) || abort \"x has to be 2 or it won't work!\"; x + y;\n n = \"-5\"; # only modify this line\nin\n\nassert (lib.isInt n) || abort \"Type error since supplied argument is no int!\";\n\nrec {\n ex00 = func (n+3) 3;\n}",
"solution": "with import <nixpkgs> {};\nlet\n func = x: y: assert (x==2) || abort \"x has to be 2 or it won't work!\"; x + y;\n n = -1;\nin\n\nassert (lib.isInt n) || abort \"Type error since supplied argument is no int!\";\nassert (lib.isInt n) -> (n > -5);\n\nrec {\n ex00 = func (n+3) 3;\n}",
"youtube": "https://www.youtube.com/watch?v=g-qDaCr2rwQ&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Debugging packaging of nano",
"path": "nano",
"question": "This is the `default.nix` of the nano text editor in nixpkgs.\n\n* find and fix all errors so that a proper `attribute set` is evaluated\n\n**Note:** We had to add some dummy functions or it wouldn't work in \nour simplified javascript environment. \n\n",
"code": "let\n #dummyfunctions\n fetchurl = x: x;\n ncurses = \"ncurses\";\n gettext = \"gettext\";\nin\nrec {\n pname = \"nano\"\n version = 2.3.6\";\n\n name = \"${pname}-${version}\";\n\n src = fetchurl {\n url = \"mirror://gnu/nano/{name}.tar.gz\";\n sha256 = \"a74bf3f18b12c1c777ae737c0e463152439e381aba8720b4bc67449f36a09534\";\n };\n\n buildInputs = [ ncurses gettext ];\n\n configureFlags = \"sysconfdir=/etc\";\n\n meta = {\n homepage = http://www.nano-editor.org/;\n description \"A small, user-friendly console text editor\";\n };\n}\n",
"solution": "let\n #dummyfunctions\n fetchurl = x: x;\n ncurses = \"ncurses\";\n gettext = \"gettext\";\nin\nrec {\n pname = \"nano\";\n version = \"2.3.6\";\n\n name = \"${pname}-${version}\";\n\n src = fetchurl {\n url = \"mirror://gnu/nano/${name}.tar.gz\";\n sha256 = \"a74bf3f18b12c1c777ae737c0e463152439e381aba8720b4bc67449f36a09534\";\n };\n\n buildInputs = [ ncurses gettext ];\n\n configureFlags = \"sysconfdir=/etc\";\n\n meta = {\n homepage = http://www.nano-editor.org/;\n description = \"A small, user-friendly console text editor\";\n };\n}\n",
"youtube": "https://www.youtube.com/watch?v=9EcFI_hFlHs&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Map",
"path": "map",
"question": "A function called `builtins.map` exists.\n\nThe `map-function` requires these arguments: a `function` and a `list`. \nIt evaluates the given function on every element of the given list. \n\nIn the example it is used to multiply \nevery number in a list by two. \n\nYour job:\n\n* Use the map function to extend every `string` in **bar** with \"bar\". \n\n**Note:** You can modify the `Strings` in any way. \nThey don't have to evaluate to 'foobar' (nor should they).",
"code": "let\n bar = [\"bar\" \"foo\" \"bla\"];\n numbers = [1 2 3 4];\nin\n{\n #multiplies every number by 2\n example = map (n: n * 2) numbers; \n #complete this\n# foobar = map ( XXX ) XXX;\n}\n",
"solution": "let\n bar = [\"bar\" \"foo\" \"bla\"];\n numbers = [1 2 3 4];\nin\n{\n #multiplies every number by 2\n example = map (n: n * 2) numbers; \n #complete this\n foobar = map (x: x + \"bar\") bar;\n}",
"youtube": "https://www.youtube.com/watch?v=4fp-7_yz07I&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "mapAttrs",
"path": "mapAttrs",
"question": "A function called `builtins.mapAttrs` exists which is similar to `builtins.map`.\n\nThe `mapAttrs`-function requires these arguments: a `function` and a `attrSet`. \n\nIt evaluates the given function on every element of the given attribute set. \n\nYour Job: \n\n * In the exercise, multiply every *value* by 7.\n\nDocumentation: <https://nixos.org/manual/nix/stable/language/builtins.html#builtins-mapAttrs>\n\n**Note**: mapAttrs is builtin but not in this old version of the tour, just use `lib.mapAttrs` instead!",
"code": "with import <nixpkgs> { };\nwith stdenv.lib;\nlet\n attrSet = { a = -2; b = 3; };\nin \n{\n ex0 = lib.mapAttrs XXX\n}\n",
"solution": "with import <nixpkgs> { };\nwith stdenv.lib;\nlet\n attrSet = { a = -2; b = 3; };\nin \n{\n ex0 = lib.mapAttrs (n: v: v * 7) attrSet;\n}\n",
"youtube": "https://www.youtube.com/watch?v=JYHTVORLGA0&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Fold: Introduction",
"path": "fold/introduction",
"question": "### Exercise\n\nYour job:\n\n* `ex0`: use `fold` to write a function that counts all `strings` \nwith value \"a\" in a given `list`\n\n* `ex1`: use `fold` to multiply each element by 2 and add the [ 8 ] to it\n\n### fold (aka foldr)\n\n`fold func init [x_1 x_2 ... x_n] == func x_1 (func x_2 ... (func x_n init))`\n\n* `func`, a function like `(el: container: container + el)`\n* `init` as the initial starting value\n\nString examples: \n\n* `lib.fold (el: c: el + c) \"z\" [ \"a\" \"b\" \"c\" ] => \"abcz\"`\n* `lib.fold (el: c: c ++ [el]) [0] [1 2 3] => [ 0 3 2 1 ]`\n\n### foldl\n\n`foldl func init [x_1 x_2 ... x_n] == func (... (func (func init x_1) x_2) ... x_n)`. \n\n* `func`, a function like `(container: el: container + el)`\n* `init` as the initial starting value\n\nList examples: \n\n* `lib.foldl (c: el: el + c) \"z\" [ \"a\" \"b\" \"c\" ] => \"cbaz\"`\n* `lib.foldl (c: el: c ++ [el]) [0] [1 2 3] => [ 0 1 2 3 ]`\n\n**Note:** See <https://nixos.org/manual/nixpkgs/stable/#chap-functions>, search **lib.lists.foldr**\n\n**Note:** See <https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-repl>\n",
"code": "with import <nixpkgs> { };\nwith lib;\nlet\n list = [\"a\" \"b\" \"a\" \"c\" \"d\" \"a\"];\n intList = [ 1 2 3 ];\n countA = XXX\n #mulB = XXX\nin\nrec {\n example = fold (x: y: x + y) \"z\" [\"a\" \"b\" \"c\"]; #is \"abcz\"\n ex0 = countA list; #should be 3\n #ex1 = mulB intList; #should be [ 2 4 6 8 ]\n}",
"solution": "with import <nixpkgs> { };\nwith lib;\nlet\n list = [\"a\" \"b\" \"a\" \"c\" \"d\" \"a\"];\n intList = [ 1 2 3 ];\n countA = l: fold (el: c: if el == \"a\" then c + 1 else c) 0 l;\n mulB = l: fold (el: c: [(el * 2)] ++ c) [8] l;\nin\nrec {\n example = fold (x: y: x + y) \"z\" [\"a\" \"b\" \"c\"]; #is \"abcz\"\n ex0 = countA list; #should be 3\n ex1 = mulB intList; #should be [ 2 4 6 8 ]\n}",
"youtube": "https://www.youtube.com/watch?v=TrUmPnKIKbI&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Reimplementation: reverseList",
"path": "reimplementation/reverselist",
"question": "Use `fold` to implement the `reverseList` function.\n\n**Note:** You basically implement the function `lib.reverseList`.\nYour function should behave exactly the same!",
"code": "with import <nixpkgs> { };\nlet\n listOfNumbers = [2 4 6 9 27];\n reverseList = lib.fold XXX;\nin\nrec {\n example = lib.reverseList listOfNumbers;\n result = reverseList listOfNumbers;\n}\n",
"solution": "with import <nixpkgs> { };\nlet\n listOfNumbers = [2 4 6 9 27];\n reverseList = lib.fold (e: acc: acc ++ [ e ]) [];\nin\nrec {\n example = lib.reverseList listOfNumbers;\n result = reverseList listOfNumbers;\n}\n",
"youtube": "https://www.youtube.com/watch?v=LApNEuzt9Is&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Fold: Implementing 'map'",
"path": "reimplementation/map",
"question": "Use `fold` to write your own `map` function.\n\n**Note:** The little error is intended, FIX IT!",
"code": "with import <nixpkgs> { };\nlet\n listOfNumbers = [2 4 6 9 27];\n myMap = XXX fold XXX; \nin\nrec {\n #your map should create the same result as the standard map function\n example = map (x: builtins.div x 2) listOfNumbers; \n result = myMap (x: builtins.div x 2) listOfNumbers;\n}\n",
"solution": "with import <nixpkgs> { };\nlet\n listOfNumbers = [2 4 6 9 27];\n myMap = op: list: lib.fold (x: y: [(op x)] ++ y) [] list; \nin\nrec {\n #your map should create the same result as the standard map function\n example = map (x: builtins.div x 2) listOfNumbers; \n result = myMap (x: builtins.div x 2) listOfNumbers;\n}\n",
"youtube": "https://www.youtube.com/watch?v=RZuWUn_QHnQ&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Reimplementation: attrVals",
"path": "reimplementation/attrVals",
"question": " Write your own implementation of the `attrVals` function.\n\n It consumes a list of `attribute names` and an \n `attribute set`. It returnes the values of each \n `attribute name`.\n \n**Note**: Remember that `attrSet ? \"a\"` returns `true` and `attrSet ? \"j\"` => `false`!\n\n**Note**: Remember that `key = a; attrSet.${a}` returns `1`!\n\n###`attrVals` vs `attrValues`: \n\n* `attrVals` -> given a list of names, extract their values from the set and return a list of them\n\n `attrVals [\"a\" \"b\" \"c\"] attrSet; => should be [1 2 3]` \n\n* `attrValues` -> extract all values in the given set and return a list of them\n\n `attrValues attrSet; => [1 2 3 4]`\n\n**Warning:** This is hard!",
"code": "with import <nixpkgs> { };\nlet\n attrSet = {c = 3; a = 1; b = 2; d=4;};\n\n #tips: use the map function and access the attribute values \n attrVals = XXX;\n\nin\nrec {\n\n solution = attrVals [\"a\" \"b\" \"c\"] attrSet; #should be [1 2 3]\n}\n",
"solution": "\nwith import <nixpkgs> { };\nlet\n attrSet = {c = 3; a = 1; b = 2; d=4;};\n attrVals = kys: se: lib.fold (el: c: if se ? \"${el}\" then [(se.${el})] ++ c else c) [] kys;\n\nin\nrec {\n\n solution = attrVals [\"a\" \"b\" \"c\"] attrSet; #should be [1 2 3]\n}\n\n",
"youtube": "https://www.youtube.com/watch?v=CQAeAyRX1zs&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Reimplementation: attrValues",
"path": "reimplementation/attrValues",
"question": " Write your own implementation of the `attrValues` function.\n\n This function consumes an `attribute set` and returns all values \n sorted by the `attribute name`.\n\n You are allowed to use the builtin function `attrNames` \n and the `attrVals` function you just implemented in the \n last lecture.\n \n### `attrVals` vs `attrValues`: \n\n* `attrVals` -> given a list of names, extract their values from the set and return a list of them\n\n `attrVals [\"a\" \"b\" \"c\"] attrSet; => should be [1 2 3]` \n\n* `attrValues` -> extract all values in the given set and return a list of them\n\n `attrValues attrSet; => [1 2 3 4]`\n\n**Warning:** This is hard!",
"code": "with import <nixpkgs> { };\nlet\n attrSet = {c = 3; a = 1; b = 2;};\n\n attrValues = XXX;\nin\nrec {\n solution = attrValues attrSet; #should be [1 2 3]\n}\n",
"solution": "with import <nixpkgs> { };\nlet\n attrSet = {c = 3; a = 1; b = 2;};\n\n attrValues = attrSet: lib.attrVals (builtins.attrNames attrSet) attrSet;\nin\nrec {\n solution = attrValues attrSet; #should be [1 2 3]\n}\n",
"youtube": "https://www.youtube.com/watch?v=oikq0CBWR4w&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "Reimplementation: catAttrs",
"path": "reimplementation/catAttrs",
"question": "Write the function `catAttrs`. \n\n `catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]; => [ 1 2 ]`\n\nAttribute sets that don't contain the named attribute are ignored.\n\n **Note:** you can use the builtin function `concatLists`.\n\n **Note:** the right-hand side of the `? operator` has the same syntax as the assignment in attrsets (i.e., `{foo=42;}` and `{\"foo\" = 42;}`)\n \n **Warning:** This is hard!",
"code": "with import <nixpkgs> { };\nlet\n list = [[\"a\"] [\"b\"] [\"c\"]];\n \n attrList = [{a = 1;} {b = 0;} {a = 2;}];\n catAttrs = XXX\nin\nrec {\n example = builtins.concatLists list; #is [ \"a\" \"b\" \"c\" ]\n result = catAttrs \"a\" attrList; #should be [1 2] \n}\n",
"solution": "with import <nixpkgs> { };\nlet\n list = [[\"a\"] [\"b\"] [\"c\"]];\n\n attrList = [{a = 1;} {b = 0;} {a = 2;}];\n catAttrs = name: List: builtins.concatLists (map (x: if x ? ${name} then [x.${name}] else []) List);\nin\nrec {\n example = builtins.concatLists list; #is [ \"a\" \"b\" \"c\" ]\n result = catAttrs \"a\" attrList; #should be [1 2] \n}\n",
"youtube": "https://www.youtube.com/watch?v=x57JiHKo7Ec&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
},
{
"topic": "The end",
"path": "end",
"question": "## It is done!\nCongratulations! You reached the end of this course and you made it!\n\n**We hope you liked 'A tour of Nix'!** If you want to get in **contact**, \nplease raise an issue at [https://github.com/nixcloud/tour_of_nix](https://github.com/nixcloud/tour_of_nix/issues)\n\n\n##Education & Consulting\n\nAn excellent resource is <https://nixos.org/community/commercial-support>\n\n## Further reading\n\n* [NixPkgs manual](https://nixos.org/nixpkgs/manual) \n\n Covers topics such as: buildPhases, override(s) and support for specific \n programming languages.\n\n* [NixOS Wiki](https://nixos.wiki/)\n\n Practical usage examples, like the \n [Cheatsheet](https://nixos.wiki/wiki/Cheatsheet).\n\n* [nix.dev](https://nix.dev/)\n\n Introduction to nix-shell, flakes and workflows.\n\n* [Nix by example](https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55)\n\n Parse trees, evaluation order, composite data-types, laziness, conditionals, Let expressions, and much more...\n\n* [Luca Bruno's nix pill(s)](https://lethalman.blogspot.de/2014/07/nix-pill-1-why-you-should-give-it-try.html)\n \n The Nix Pills are a wonderful introduction into Nix programming and you will \n have much joy reading them!\n\n## Donations\n\nFinancial support for hosting the tour of nix is appreciated: \n\n ??PAYPAL??\n\n##Contributing\n\nYou are welcome to extend the tour of nix, it is an open source project! Create issues on <https://github.com/nixcloud/tour_of_nix/issues> or modify the questions.json and create a PR!\n\n### Manual editing\nDownload <https://nixcloud.io/tour/questions.json> and open it in the \neditor of your choise.\n\n### Using the inline editor\n\nShortcuts:\n\n* `ctrl+,` - loads markdown into the editor\n* `ctrl+.` - compiles markdown2html into the right side\n\n **Note:** do this twice and the editor is restored to the previous state!\n\n* `ctrl+i` - reset the editor to the default content\n* `ctrl+s` - save the questions to `questions.json` into you \n `downloads` directory\n \nIf you want to add new questions, use the javascript console. \n\n**Warning:** `ctrl+shift+i` won't work in chrome, so use the mouse with \nRMB to `inspect element`. From that javascript console you can extend the `questions` \nobject, which holds all the questions.\n\n**Warning:** You might want to play with the workflow for some time as\nyou can easily 'overwrite' or 'reset' your contributions by accident!",
"code": "with import <nixpkgs> { }; \nrec {\n made_it = \"it is done\";\n}\n",
"solution": "with import <nixpkgs> { }; \nrec {\n made_it = \"it is done\";\n}\n",
"youtube": "https://www.youtube.com/watch?v=qWxGtbeRGhU&list=PLMr2KA8WWojv-4cgqIiVebml0FrMl8N_-"
}
]