Monday, July 28, 2014

Nix pill 5: functions and imports

Welcome to the fifth Nix pill. In the previous fourth pill we touched the Nix language for a moment. We introduced basic types and values of the Nix language, and basic expressions such as "if", "with" and "let". I invite you to re-read about these expressions and play with them in the repl.

Functions help to build reusable components in a big repository like nixpkgs. The Nix manual has a great explanation of functions. Let's go: pill on one hand, Nix manual on the other hand.

I remind you how to enter the Nix environment: source ~/.nix-profile/etc/profile.d/nix.sh

Nameless and single parameter


Functions are anonymous (lambdas), and only have a single parameter. The syntax is extremely simple. Type the parameter name, then ":", then the body of the function.
nix-repl> x: x*2
«lambda»
So here we defined a function that takes a parameter x, and returns x*2. The problem is that we cannot use it in any way, because it's unnamed... joke!
We can store functions in variables.
nix-repl> double = x: x*2
nix-repl> double
«lambda»
nix-repl> double 3
6
As usual, please ignore the special syntax for assignments inside nix-repl.
So, we defined a function x: x*2 that takes one parameter x, and returns x*2. This function is then assigned to the variable double.
Finally we did our first function call: double 3.
Big note: it's not like many other programming languages where you write double(3). It really is double 3.

In summary: to call a function, name the variable, then space, then the argument. Nothing else to say, it's as easy as that.

More than one parameter


How do we create a function that accepts more than one parameter? For people not used to functional programming, this may take a while to grasp. Let's do it step by step.
nix-repl> mul = a: (b: a*b)
nix-repl> mul
«lambda»
nix-repl> mul 3
«lambda»
nix-repl> (mul 3) 4
12
We defined a function that takes the parameter "a", the body returns another function. This other function takes a parameter "b" and returns a*b.
Therefore, calling "mul 3" returns this kind of function: b: 3*b. In turn, we call the returned function with 4, and get the expected result.

You don't have to use parenthesis at all, Nix has sane priorities when parsing the code:
nix-repl> mul = a: b: a*b
nix-repl> mul
«lambda»
nix-repl> mul 3
«lambda»
nix-repl> mul 3 4
12
nix-repl> mul (6+7) (8+9)
221
Much more readable, you don't even notice that functions only receive one argument.
Since the argument is separated by a space, to pass more complex expressions you need parenthesis. In other common languages you would write  mul(6+7, 8+9).

Given that functions have only one parameter, it is straightforward to use partial application:
nix-repl> foo = mul 3
nix-repl> foo 4
12
nix-repl> foo 5
15
We stored the function returned by mul 3 into a variable foo, then reused it.

Arguments set


Now this is a very cool feature of Nix. It is possible to pattern match over a set in the parameter. We write an alternative version of mul = a: b: a*b first by using a set as argument, then using pattern matching.
nix-repl> mul = s: s.a*s.b
nix-repl> mul { a = 3; b = 4; }
12
nix-repl> mul = { a, b }: a*b
nix-repl> mul { a = 3; b = 4; }
12
In the first case we defined a function that accepts a single parameter. We then access attributes "a" and "b" from the given set.
Note how the parenthesis-less syntax for function calls is very elegant in this case, instead of doing mul({ a=3; b=4; }) in other languages.

In the second case we defined an arguments set. It's like defining a set, except without values. We require that the passed set contains the keys "a" and "b". Then we can use those "a" and "b" in the function body directly.
nix-repl> mul { a = 3; b = 4; c = 6; }
error: anonymous function at (string):1:2 called with unexpected argument `c', at (string):1:1
nix-repl> mul { a = 3; }
error: anonymous function at (string):1:2 called without required argument `b', at (string):1:1
Only a set with exactly the attributes required by the function is accepted, nothing more, nothing less.

Default and variadic attributes


It is possible to specify default values of attributes in the arguments set:
nix-repl> mul = { a, b ? 2 }: a*b
nix-repl> mul { a = 3; }
6
nix-repl> mul { a = 3; b = 4; }
12
Also you can allow passing more attributes (variadic) than the expected ones:
nix-repl> mul = { a, b, ... }: a*b
nix-repl> mul { a = 3; b = 4; c = 2; }
However, in the function body you cannot access the "c" attribute. The solution is to give a name to the given set with the @-pattern:
nix-repl> mul = s@{ a, b, ... }: a*b*s.c
nix-repl> mul { a = 3; b = 4; c = 2; }
24
That's it, you give a name to the whole parameter with name@ before the set pattern.

Advantages of using argument sets:
  • Named unordered arguments: you don't have to remember the order of the arguments.
  • You can pass sets, that adds a whole new layer of flexibility and convenience. 
Disadvantages:
  • Partial application does not work with argument sets. You have to specify the whole attribute set, not part of it.
You may find similarities with Python **kwargs.

Imports


The "import" function is built-in and provides a way to parse a .nix file. The natural approach is to define each component in a .nix file, then compose by importing these files.

Let's start with the bare metal.

a.nix:
3
b.nix:
4
mul.nix:
a: b: a*b
nix-repl> a = import ./a.nix
nix-repl> b = import ./b.nix
nix-repl> mul = import ./mul.nix
nix-repl> mul a b
12
Yes it's really that straight. You import a file, and it gets parsed as expression. Note that the scope of the imported file does not inherit the scope of the importer.

test.nix:
x
nix-repl> let x = 5; in import ./test.nix
error: undefined variable `x' at /home/lethal/test.nix:1:1
So how do we pass information to the module? Use functions, like we did with mul.nix .
A more complex example:

test.nix:
{ a, b ? 3, trueMsg ? "yes", falseMsg ? "no" }:
if a > b
  then builtins.trace trueMsg true
  else builtins.trace falseMsg false
nix-repl> import ./test.nix { a = 5; trueMsg = "ok"; }
trace: ok
true
Explaining:
  • In test.nix we return a function. It accepts a set, with default attributes b, trueMsg and falseMsg.
  • builtins.trace is a built-in function that takes two arguments. The first is the message to display, the second is the value to return. It's usually used for debugging purposes.
  • Then we import test.nix, and call the function with that set.
So when is the message shown? Only when it's in need to be evaluated.

Next pill


...we will finally write our first derivation.

Nix pill 6 is available for reading here.

To be notified about the new pill, stay tuned on #NixPills, follow @lethalman or subscribe to the nixpills rss.

15 comments:

Anonymous said...

luca, I guess the links to "anchors" in the nix[os] manual are based on auto-generated random IDs which are not stable when the manual gets updated, so many of them are broken.

thanks for the tutorial, pal!

Arunvijay said...

Good post....
Coronavirus Update
Intern Ship In Chennai
Inplant Training In Chennai
Internship For CSE Students
Online Internships
Internship For MBA Students
ITO Internship

Digitalsashi said...

Thanks for your post! Really interesting blogs.

Digital marketing company | Digital Marketing Agency | Digital Marketing Companies in Bangalore
Digital marketing agency in hyderabad | Digital marketing companies in hyderabad

Digitalsashi said...

The post was really very good. Thanks for sharing.

SEO company in bangalore | SEO services in bangalore

Lord Of The Maverick said...

kıl çadır
kıl çadır nedir
kıl çadır fiyatları sahibinden
kıl çadırı düğün salonu
yörük çadır
osmanlı çadır
otağ kıl çadır
Katı meyve sıkacağı
meyve sıkacağı
sebze sıkacağı
kereviz sıkacağı
kereviz sapı ne işe yarar
kereviz sapı ile ne yapılır
En iyi Katı meyve sıkacağı
blender
hurom
cold press
bebek katı meyve sıkacağı

Lord Of The Maverick said...

kokteyl catering
kokteyl catering fiyatları
istanbul kokteyl catering
catering kokteyl menüleri
fuar yemek organizasyon
fuar yemek organizasyo firmaları
fuar için yemek firmaları
düğün yemek organizasyonu
düğün yemek organizasyonu yapan firmalar
istanbul kokteyl catering
istanbul kokteyl catering firmaları
Kokteyl catering fiyatları
istanbul catering firmaları listesi
istanbul catering şirketleri
istanbul Fuar catering Hizmetleri
catering şirketleri istanbul
istanbul daki catering firmaları
300 kişilik yemek Fiyatları
istanbul fuar yemek organizasyonn
istanbul fuar yemek organizasyon firmaları
istanbul fuar için yemek firmaları

Lord Of The Maverick said...

Şark Odası
Şark Köşesi
Cami Kapısı
Bahçe Kapısı
kündekari Kapı
ahşap kündekari Kapı
Ahşap Kapı İmalatı
İstanbul Şark Odası
İstanbul Şark Köşesi
İstanbul Cami Kapısı
İstanbul Ahşap Kapı İmalatı
Adana Şark Odası
Adana Şark Köşesi
Adana Cami Kapısı
Adana Ahşap Kapı İmalatı
Gaziantep Şark Odası
Gaziantep Şark Köşesi
Gaziantep Cami Kapısı
Gaziantep Ahşap Kapı İmalatı
bursa Şark Odası
bursa Şark Köşesi
bursa Cami Kapısı
bursa Ahşap Kapı İmalatı

Lord Of The Maverick said...

istanbul psikolog
istanbul terapist
Yaşlılık Depresyonu Tedavisi
Yaşlılık Depresyonu Nedenleri
Yaşlılık Depresyonu İçin Öneriler
istanbul avrupa yakası psikolog

Lord Of The Maverick said...

Bayrampaşa Su Kaçağı Bulma
Bayrampaşa Su Kaçağı Tespiti
Bayrampaşa Noktasal Su Kaçağı Tespiti
Bayrampaşa Kırmadan Su Kaçağı Tespiti
Bayrampaşa kamera İle Su Kaçağı Tespiti
Bayrampaşa Noktasal Su Kaçağı Bulma
Bayrampaşa Kırmadan Su Kaçağı Bulma
Bayrampaşa kamera İle Su Kaçağı Bulma
Noktasal Su Kaçağı Tespiti Bayrampaşa
Kırmadan Su Kaçağı Tespiti Bayrampaşa
kamera İle Su Kaçağı Tespiti Bayrampaşa
Su Kaçağı Bulma Bayrampaşa
Noktasal Su Kaçağı Bulma Bayrampaşa
Kırmadan Su Kaçağı Bulma Bayrampaşa
Gaziosmanpaşa su kaçağı bulma
Gaziosmanpaşa su kaçağı tespiti
Gaziosmapaşa Noktasal Su kaçağı Tespiti
Gaziosmanpaşa Kırmadan Su Kaçağı tespiti
Gaziosmanpaşa Su tesisatçısı
Zeytinburnu su kaçağı bulma
Zeytinburnu su kaçağı tespiti
Zeytinburnu Noktasal Su kaçağı Tespiti
Zeytinburnu Kırmadan Su Kaçağı tespiti
Zeytinburnu Su tesisatçısı
Eyüp su kaçağı bulma
Eyüp su kaçağı tespiti
Eyüp Noktasal Su kaçağı Tespiti
Eyüp Kırmadan Su Kaçağı tespiti
Eyüp Su tesisatçısı
Esenler su kaçağı bulma
Esenler su kaçağı tespiti
Esenler Noktasal Su kaçağı Tespiti
Esenler Kırmadan Su Kaçağı tespiti
Esenler Su tesisatçısı

Lord Of The Maverick said...

dezenfektan aparatı
el dezenfektanı fiyatları
el dezenfektanı aparatı
en iyi el dezenfektanı
el dezenfektan aparatı
el dezenfektanı duvar aparatı fiyatı
dezenfektan tutucu
el dezenfektanı makinesi
el dezenfektanı duvar aparatı
el dezenfektanı aparatı fiyatı
el dezenfektanı askı aparatı
dezenfektan aparatı kolu
Dezenfektan Duvar Askı Aparatı
Dezenfektan Ayağı
Dezenfektan Ahşap Ayalık
Dezenfektan Standı
Ayaklı El Dezenfektan Standı

aydın boyacı
aydın boya fiyatları
aydın boya ustası
aydın badana ustası
aydın boyacı fiyatları
boyacı fiyatları
Badana Ustası Fiyatları

Secesta said...

en koleji
Başarmak İsteyenlerin Adresi En koleji

en koleji
Başarmak İsteyenlerin Adresi En koleji

en koleji
Başarmak İsteyenlerin Adresi En koleji

en koleji
Başarmak İsteyenlerin Adresi En koleji

en koleji
Başarmak İsteyenlerin Adresi En koleji

psikolog

divvidivya said...

Nice Blog. Are you looking for a best Digital Marketing Company in Hyderabad visit 9and9.

Birol Sarıteke said...

Sağlık Haberleri Sağlıklı Yaşam ve Beslenme Sağlık alanından en son araştırmalar, sağlıklı yaşam için gereklilikler, diyetler, beslenme şekilleri, hastalıklar ve yeni tedavi yöntemleri hakkında güncel bilgiler.

Unknown said...

Thanks for sharing this useful Blog. For all Digital Marketing Services In Hyderabad visit 9and9.

pandith13 said...

Great post, thanks
SRI ANNAPOORNESHAWARI ASTROLOGY CENTER.Best Astrologer In Pennsylvania