Category Archives: Haskell

Haskell – 143 – elementi base del linguaggio – 6

Continuo da qui, copio qui.

Now that we’ve seen how to write code in a file, we can start writing functions. As you might have expected, functions are central to Haskell, as it is a functional language. This means that the evaluation of a program is simply the evaluation of a function.

We can write a simple function to square a number and enter it into our Test.hs file. We might define this as follows:

square x = x * x

In this function definition, we say that we’re defining a function square that takes one argument (aka parameter), which we call x. We then say that the value of square x is equal to x * x.

Haskell also supports standard conditional expressions. For instance, we could define a function that returns -1 if its argument is less than 0; 0 if its argument is 0; and 1 if its argument is greater than 0} (this is called the signum function):

signum x =
  if x  0
      then 1
      else 0

Invece di aggiornate Test.hs del post precedente ne costruisco uno nuovo, con solo quel che serve.


module Test

signum x =
  if x  0
      then 1
      else 0

You can experiment with this as:

* hs-143 $ ghci Test
GHCi, version 8.0.2:  :? for help
[1 of 1] Compiling Test             ( Test.hs, interpreted )
Ok, modules loaded: Test.
*Test> signum 5

:1:1: error:
    Ambiguous occurrence ‘signum’
    It could refer to either ‘Prelude.signum’,
                             imported from ‘Prelude’ at Test.hs:1:8-11
                             (and originally defined in ‘GHC.Num’)
                          or ‘Test.signum’, defined at Test.hs:4:1

OOPS! quale signum voglio usare? Modifico Test.hs chiamando la funzione signum'.

* hs-143 $ ghci Test
GHCi, version 8.0.2:  :? for help
[1 of 1] Compiling Test             ( Test.hs, interpreted )
Ok, modules loaded: Test.
*Test> signum' 5
*Test> signum' 0
*Test> signum' (5 - 10)
*Test> signum' (-1)

Note that the parenthesis around “-1” in the last example are required; if missing, the system will think you are trying to subtract the value “1” from the value “signum',” which is illtyped.

The if/then/else construct in Haskell is very similar to that of most other programming languages; however, you must have both a then and an else clause. It evaluates the condition (in this case x<0 and, if this evaluates to True, it evaluates the then clause; if the condition evaluated to False, it evaluates the else clause).

You can test this program by editing the file and loading it back into your interpreter. If Test is already the current module, instead of typing :l Test.hs again, you can simply type :reload or just :r to reload the current file. This is usually much faster.

Haskell, like many other languages, also supports case constructions. These are used when there are multiple values that you want to check against (case expressions are actually quite a bit more powerful than this — see the section on Pattern matching [prossimamente] for all of the details).

Suppose we wanted to define a function that had a value of 1 if its argument were 0; a value of 5 if its argument were 1; a value of 2 if its argument were 2; and a value of -1 in all other instances. Writing this function using if statements would be long and very unreadable; so we write it using a case statement as follows (we call this function f):

f x =
  case x of
    0 -> 1
    1 -> 5
    2 -> 2
    _ -> -1

In this program, we’re defining f to take an argument x and then inspect the value of x. If it matches 0, the value of f is 1. If it matches 1, the value of f is 5. If it maches 2, then the value of f is 2; and if it hasn’t matched anything by that point, the value of f is -1 (the underscore can be thought of as a “wildcard” –it will match anything).

The indentation here is important. Haskell uses a system called “layout” to structure its code (the programming language Python uses a similar system). The layout system allows you to write code without the explicit semicolons and braces that other languages like C and Java require.

Note: Because whitespace matters in Haskell, you need to be careful about whether you are using tabs or spaces. If you can configure your editor to never use tabs, that’s probably better. If not, make sure your tabs are always 8 spaces long, or you’re likely to run in to problems.

The general rule for layout is that an open-brace is inserted after the keywords where, let, do and of, and the column position at which the next command appears is remembered. From then on, a semicolon is inserted before every new line that is indented the same amount. If a following line is indented less, a close-brace is inserted. This may sound complicated, but if you follow the general rule of indenting after each of those keywords, you’ll never have to remember it (see the section on Layout [prossimamente] for a more complete discussion of layout).

Some people prefer not to use layout and write the braces and semicolons explicitly. This is perfectly acceptable. In this style, the above function might look like:

f x = case x of
  { 0 -> 1 ; 1 -> 5 ; 2 -> 2 ; _ -> -1 }

Nota: in questo caso la seconda riga dev’essere indentata, ma non importa di quanto; io sono per 2 spazi.

Of course, if you write the braces and semicolons explicitly, you’re free to structure the code as you wish. The following is also equally valid:

f x =
    case x of { 0 -> 1 ;
      1 -> 5 ; 2 -> 2
   ; _ -> -1 }

However, structuring your code like this only serves to make it unreadable (in this case).

Functions can also be defined piece-wise, meaning that you can write one version of your function for certain parameters and then another version for other parameters. For instance, the above function f could also be written as:

f 0 = 1
f 1 = 5
f 2 = 2
f _ = -1

Here, the order is important. If we had put the last line first, it would have matched every argument, and f would return -1, regardless of its argument (most compilers will warn you about this, though, saying something about overlapping patterns). If we had not included this last line, f would produce an error if anything other than 0, 1 or 2 were applied to it (most compilers will warn you about this, too, saying something about incomplete patterns). This style of piece-wise definition is very popular and will be used quite frequently throughout this tutorial. These two definitions of f are actually equivalent — this piece-wise version is translated into the case expression.

More complicated functions can be built from simpler functions using function composition. Function composition is simply taking the result of the application of one function and using that as an argument for another. We’ve already seen this way back in arithmetic (the section on Arithmetic [qui]), when we wrote 5*4+3. In this, we were evaluating 5*4 and then applying +3 to the result. We can do the same thing with our square and f functions (creo TestF.hs contenente queste funzioni):

* hs-143 $ ghci TestF
GHCi, version 8.0.2:  :? for help
[1 of 1] Compiling TestF            ( TestF.hs, interpreted )
Ok, modules loaded: TestF.
*TestF> square (f 1)
*TestF> square (f 2)
*TestF> f (square 1)
*TestF> f (square 2)

The result of each of these function applications is fairly straightforward. The parentheses around the inner function are necessary; otherwise, in the first line, the interpreter would think that you were trying to get the value of “square f“, which has no meaning. Function application like this is fairly standard in most programming languages. There is another, more mathematically oriented, way to express function composition, using the . (just a single period) function. This . function is supposed to look like the operator in mathematics. Nota: ho tolto le parentesi.

Note: In mathematics we write f ∘ g to mean “f following g,” in Haskell we write f . g also to mean “f following g.”
The meaning of f ∘ g is simply that (f ∘ g) (x) = f (g (x)). That is, applying the value x to the function f ∘ g is the same as applying it to g, taking the result, and then applying that to f.

The (.) function (called the function composition function), takes two functions and makes them in to one. For instance, if we write (square . f), this means that it creates a new function that takes an argument, applies f to that argument and then applies square to the result. Conversely, (f . square) means that it creates a new function that takes an argument, applies square to that argument and then applies f to the result. We can see this by testing it as before:

*TestF> (square . f) 1
*TestF> (square . f) 2
*TestF> (f . square) 1
*TestF> (f . square) 2

Here, we must enclose the function composition in parentheses; otherwise, the Haskell compiler will think we’re trying to compose square with the value f 1 in the first line, which makes no sense since f 1 isn’t even a function.

It would probably be wise to take a little time-out to look at some of the functions that are defined in the Prelude. Undoubtedly, at some point, you will accidentally rewrite some already-existing function (I’ve done it more times than I can count), but if we can keep this to a minimum, that would save a lot of time. Here are some simple functions, some of which we’ve already seen:

sqrt  the square root function
id    the identity function: id x = x
fst   extracts the first element from a pair
snd   extracts the second element from a pair
null  tells you whether or not a list is empty
head  returns the first element on a non-empty list
tail  returns everything but the first element of a non-empty list
++    concatenates two lists
==    checks to see if two elements are equal
/=    checks to see if two elements are unequal

Here, we show example usages of each of these functions:

Prelude> sqrt 2
Prelude> id "hello"
Prelude> id 5
Prelude> fst (5,2)
Prelude> snd (5,2)
Prelude> null []
Prelude> null [1,2,3,4]
Prelude> head [1,2,3,4]
Prelude> tail [1,2,3,4]
Prelude> [1,2,3] ++ [4,5,6]
Prelude> [1,2,3] == [1,2,3]
Prelude> 'a' /= 'b'
Prelude> head []
*** Exception: Prelude.head: empty list

We can see that applying head to an empty list gives an error (the exact error message depends on whether you’re using GHCi or Hugs.



Haskell – 142 – elementi base del linguaggio – 5

Continuo da qui, copio qui.

Files sorgenti
As programmers, we don’t want to simply evaluate small expressions like these — we want to sit down, write code in our editor of choice, save it and then use it.

We already saw […] how to write a Hello World program and how to compile it. OOPS, saltato, era solo introdittiva, meglio vederlo qui per bene. Here, we show how to use functions defined in a source-code file in the interactive environment. To do this, create a file called Test.hs and enter the following code:


module Test

x = 5
y = (6, "Hello")
z = x * fst y

This is a very simple “program” written in Haskell. It defines a module called “Test” (in general module names should match file names; see the section on Modules for more on this [prossimamente]). In this module, there are three definitions: x, y and z. Once you’ve written and saved this file, in the directory in which you saved it, load this in your favorite interpreter [io GHC], by executing either of the following:

* hs-142 $ ghci Test.hs
GHCi, version 8.0.2:  :? for help
[1 of 1] Compiling Test             ( Test.hs, interpreted )
Ok, modules loaded: Test.

This will start Hugs or GHCi, respectively, and load the file. Alternatively, if you already have one of them loaded, you can use the “:load” command (or just “:l“) to load a module as: :l Test.hs.

Between the first and last line, the interpreter will print various data to explain what it is doing. If any errors appear, you probably mistyped something in the file; double check and then try again.

You’ll notice that where it used to say “Prelude” it now says “Test“. That means that Test is the current module. The Prelude module (usually simply referred to as “the Prelude”) is always loaded and contains the standard definitions (for instance, the (:) operator for lists, or (+) or (*), fst, snd and so on).

Now that we’ve loaded Test, we can use things that were defined in it. For example:

*Test> x
*Test> y
*Test> z

Perfect, just as we expected!

One final issue regarding how to compile programs to stand-alone executables remains. In order for a program to be an executable, it must have the module name “Main” and must contain a function called main. So, if you go in to Test.hs and rename it to “Main” (change the line that reads module Test to module Main), we simply need to add a main function.


module Main

x = 5
y = (6, "Hello")
z = x * fst y

main = putStrLn "Hello World"

Now, save the file, and compile it […]. For example, in GHC, you would say:

* hs-142 $ ghc --make Main.hs -o main
[1 of 1] Compiling Main             ( Main.hs, Main.o )
Linking main ...

Il tutorial usa il nome Test ma credo sia in errore. Sarebbero da approfondire le opzioni; inquesto caso “--make” si può omettere.

This will create a file called “main” (or on Windows, “main.exe“) that you can then run.

* hs-142 $ ./main
Hello World

Pausa, prima di affrontare un argomento lungo.


Haskell – 141 – elementi base del linguaggio – 4

Continuo da qui, copio qui.

In Haskell, a String is simply a list of Chars. So, we can create the string "Hello" as:

Prelude> 'H':'e':'l':'l':'o':[]

Lists (and, of course, strings) can be concatenated using the ++ operator:

Prelude> "Hello " ++ "World"
"Hello World"

Additionally, non-string values can be converted to strings using the show function, and strings can be converted to non-string values using the read function. Of course, if you try to read a value that’s malformed, an error will be reported (note that this is a run-time error, not a compile-time error):

Prelude> "Five squared is " ++ show (5*5)
"Five squared is 25"
Prelude> read "5" + 3
Prelude> read "Hello" + 3
*** Exception: no parse

In the above, the exact error message is implementation dependent. However, the interpreter has inferred that you’re trying to add three to something. This means that when we execute read "Hello", we expect to be returned a number. However, "Hello" cannot be parsed as a number, so an error is reported.

Funzioni semplici per le liste
Much of the computation in Haskell programs is done by processing lists. There are three primary list-processing functions: map, filter and foldr (also foldl).

The map function takes as arguments a list of values and a function that should be applied to each of the values. It returns the result of this application. For instance, there is a built-in function Data.Char.toUpper that takes as input a Char and produces a Char that is the upper-case version of the original argument. So, to convert an entire string (which is simply a list of characters) to upper case, we can map the toUpper function across the entire list:

Prelude> map Data.Char.toUpper "Hello World"

Note: Hugs users: Hugs doesn’t like qualified names like Data.Char.toUpper. In Hugs, simply use toUpper. If toUpper is undefined, use :load Data.Char.

When you map across a list, the length of the list never changes — only the individual values in the list change.

To remove elements from the list, you can use the filter function. This function allows you to remove certain elements from a list depending on their value, but not on their context. For instance, the function Data.Char.isLower tells you whether a given character is lower case. We can filter out all non-lowercase characters using this:

Prelude> filter Data.Char.isLower "Hello World"

The function foldr takes a little more getting used to. foldr takes three arguments: a function, an initial value and a list. The best way to think about foldr is that it replaces occurrences of the list cons operator (:) with the function parameter and replaces the empty list constructor ([]) with the initial value. Thus, if we have a list:

3 : 8 : 12 : 5 : []

and we apply foldr (+) 0 to it, we get:

3 + 8 + 12 + 5 + 0

which sums the list. We can test this:

Prelude> foldr (+) 0 [3,8,12,5]

We can perform the same sort of operation to calculate the product of all the elements on a list:

Prelude> foldr (*) 1 [4,8,5]

We said earlier that folding is like replacing (:) with a particular function and ([]) with an initial element. This raises a question as to what happens when the function isn’t associative (a function () is associative if a ⋅ (b ⋅ c) = (a ⋅ b) ⋅ c. When we write 4 ⋅ 8 ⋅ 5 ⋅ 1, we need to specify where to put the parentheses. Namely, do we mean ((4 ⋅ 8) ⋅ 5) ⋅ 1 or 4 ⋅ (8 ⋅ (5 ⋅ 1))? foldr assumes the function is right-associative (i.e., the correct bracketing is the latter). Thus, when we use it on a non-associative function (like minus), we can see the effect:

Prelude> foldr (-) 1 [4,8,5]

The exact derivation of this looks something like:

     foldr (-) 1 [4,8,5]
==>  4 - (foldr (-) 1 [8,5])
==>  4 - (8 - foldr (-) 1 [5])
==>  4 - (8 - (5 - foldr (-) 1 []))
==>  4 - (8 - (5 - 1))
==>  4 - (8 - 4)
==>  4 - 4
==>  0

The foldl function goes the other way and effectively produces the opposite bracketing. foldl looks the same when applied, so we could have done summing just as well with foldl:

Prelude> foldl (+) 0 [3,8,12,5]

However, we get different results when using the non-associative function minus:

Prelude> foldl (-) 1 [4,8,5]

This is because foldl uses the opposite bracketing. The way it accomplishes this is essentially by going all the way down the list, taking the last element and combining it with the initial value via the provided function. It then takes the second-to-last element in the list and combines it to this new value. It does so until there is no more list left.

The derivation here proceeds in the opposite fashion:

     foldl (-) 1 [4,8,5]
==>  foldl (-) (1 - 4) [8,5]
==>  foldl (-) ((1 - 4) - 8) [5]
==>  foldl (-) (((1 - 4) - 8) - 5) []
==>  ((1 - 4) - 8) - 5
==>  ((-3) - 8) - 5
==>  (-11) - 5
==>  -16

Note that once the foldl goes away, the parenthesization is exactly the opposite of the foldr.

Note: foldl is often more efficient than foldr for reasons that we will discuss in the section on Lists [prossimamente]. However, foldr can work on infinite lists, while foldl cannot. This is because before foldl does anything, it has to go to the end of the list. On the other hand, foldr starts producing output immediately. For instance, foldr (:) [] [1,2,3,4,5] simply returns the same list. Even if the list were infinite, it would produce output. A similar function using foldl would fail to produce any output.

If this discussion of the folding functions is still somewhat unclear, that’s okay. We’ll discuss them further in the section on Lists [prossimamente].

Use map to convert a string into a list of booleans, each element in the new list representing whether or not the original element was a lower-case character. That is, it should take the string "aBCde" and return [True,False,False,True,True].

Prelude> map Data.Char.isUpper "aBCde"

Use the functions mentioned in this section (you will need two of them) to compute the number of lower-case letters in a string. For instance, on "aBCde" it should return 3.

Prelude> length (filter Data.Char.isLower "aBCde")

We’ve seen how to calculate sums and products using folding functions. Given that the function max returns the maximum of two numbers, write a function using a fold that will return the maximum value in a list (and zero if the list is empty). So, when applied to [5,10,2,8,1] it will return 10. Assume that the values in the list are always ≥ 0. Explain to yourself why it works.

Prelude> foldr max 0 [5, 10, 2, 8, 1]

Non ci sono riuscito, ho guardato la soluzione qui: — 3.5. E pensare che dopo risulta semplicissimo; approfondire foldr.

Write a function that takes a list of pairs of length at least 2 and returns the first component of the second element in the list. So, when provided with [(5,'b'),(1,'c'),(6,'a')], it will return 1.

Prelude> fst (head (tail [(5,'b'),(1,'c'),(6,'a')]))

Questo l’ho fatto io; ho controllato la soluzione (– 36) ed è davvero così.


Haskell – 140 – elementi base del linguaggio – 3

Continuo da qui, copio qui.

Coppie, triple e tuple più lunghe
In addition to single values, we should also address multiple values. For instance, we may want to refer to a position by its x / y coordinate, which would be a pair of integers. To make a pair of integers is simple: you enclose the pair in parenthesis and separate them with a comma:

Prelude> (5,3)

Here, we have a pair of integers, 5 and 3. In Haskell, the first element of a pair need not have the same type as the second element: that is, pairs are allowed to be heterogeneous. For instance, you can have a pair of an integer with a string. This contrasts with lists, which must be made up of elements of all the same type (we will discuss lists further in the section on Lists).

There are two predefined functions that allow you to extract the first and second elements of a pair. They are, respectively, fst and snd:

Prelude> fst (5, "hello")
Prelude> snd (5, "hello")

In addition to pairs, you can define triples, quadruples etc. To define a triple and a quadruple, respectively, we write:

Prelude> (1,2,3)
Prelude> (1,2,3,4)

And so on. In general, pairs, triples, and so on are called tuples and can store fixed amounts of heterogeneous data.

Note: The functions fst and snd won’t work on anything longer than a pair; if you try to use them on a larger tuple, you will get a message stating that there was a type error. The meaning of this error message will be explained in the chapter Type basics [prossimamente].

Exercises: Use a combination of fst and snd to extract the character 'a'
out of the tuple ((1,'a'),"foo").

Prelude> snd (fst ((1,'a'),"foo"))

Ancora non visto ma si può fare anche così:

Prelude> snd $ fst ((1,'a'),"foo")

The primary limitation of tuples is that they hold only a fixed number of elements: pairs hold two, triples hold three, and so on. A data structure that can hold an arbitrary number of elements is a list. Lists are assembled in a very similar fashion to tuples, except that they use square brackets instead of parentheses. We can define a list like:

Prelude> [1,2]
Prelude> [1,2,3]

Lists don’t need to have any elements. The empty list is simply [].

Unlike tuples, we can very easily add an element on to the beginning of the list using the colon operator. The colon is called the “cons” operator; the process of adding an element is called “consing.” The etymology of this is that we are constructing a new list from an element and an old list. We can see the cons operator in action in the following examples:

Prelude> 0:[1,2]
Prelude> 5:[1,2,3,4]

We can actually build any list by using the cons operator (the colon) and the empty list:

Prelude> 5:1:2:3:4:[]

In fact, the [5,1,2,3,4] syntax is “syntactic sugar” for the expression using the explicit cons operators and empty list. If we write something using the [5,1,2,3,4] notation, the compiler simply translates it to the expression using (:) and [].

Note: In general, “syntactic sugar” is a strictly unnecessary language feature, which is added to make the syntax nicer.

One further difference between lists and tuples is that, while tuples are heterogeneous, lists must be homogeneous. This means that you cannot have a list that holds both integers and strings. If you try to, a type error will be reported.

Of course, lists don’t have to just contain integers or strings; they can also contain tuples or even other lists. Tuples, similarly, can contain lists and other tuples:

Prelude> [(1,1),(2,4),(3,9),(4,16)]
Prelude> ([1,2,3,4],[5,6,7])

There are two basic list functions: head and tail. The head function returns the first element of a (non-empty) list, and the tail function returns all but the first element of a (non-empty) list.

To get the length of a list, you use the length function:

Prelude> length [1,2,3,4,10]
Prelude> head [1,2,3,4,10]
Prelude> length (tail [1,2,3,4,10])


Haskell – 139 – elementi base del linguaggio – 2

Continuo da qui, copio qui.

Operazioni aritmetiche
Let’s begin our foray into Haskell with simple arithmetic. Start GHCi. From here, you can begin to evaluate expressions. Provo:

Prelude> 5*4+3
Prelude> 3+5*4
Prelude> 3 + 5 * 4
Prelude> 3 + 5 * 2^2
Prelude> (3+5)*4
Prelude> 2^5+10
Prelude> sqrt 2

We can see that, in addition to the standard arithmetic operations, Haskell also allows grouping by parentheses, hence the difference between the values of 3+5*4 and (3+5)*4. The reason for this is that the “understood” grouping of the first expression is (5*4)+3, due to operator precedence.

Also note that parentheses aren’t required around function arguments. For instance, we simply wrote sqrt 2, not sqrt(2), as would be required in most other languages. You could write it with the parentheses, but in Haskell, since function application is so common, parentheses aren’t required.

Note: Even though parentheses are not always needed, sometimes it is better to leave them in anyway; other people will probably have to read your code, and if extra parentheses make the intent of the code clearer, use them.

Now try entering 2^5000. Does it work? Yepp:

Prelude> 2^5000

Nota: era una riga unica ho inserito gli a-capo.

Ah! Ormai sono tanti i linguaggi che supportano la precisione arbitraria per gli interi, Racket (expt 2 5000), provate voi. Sì, anche Python 2**5000. Il primo è stato dc 2 5000 ^ p, poi bc 2^5000 che in Unix, con una sintassi più umana, usava dc (su Linux è indipendente da dc).

We’ve seen that multiplication binds more tightly than addition. Can you think of a way to determine whether function application binds more or less tightly than multiplication?

Prelude> sqrt 2 * 10


Haskell – 138 – elementi base del linguaggio – 1

Haskell – 138 – elementi base del linguaggio – 1

Continuo da qui, copio qui.

In this chapter we present the basic concepts of Haskell. OK, ripasso, così mi abituo: mi viene sempre da pensare a Python, Racket, Julia e altri linguaggi “normali” 😐

In addition to familiarizing you with the interactive environments and showing you how to compile a basic program, we introduce the basic syntax of Haskell, which will probably be quite alien if you are used to languages like C and Java. Ecco, proprio come dicevo.

However, before we talk about specifics of the language, we need to establish some general properties of Haskell. Most importantly, Haskell is a lazy language, which means that no computation takes place unless it is forced to take place when the result of that computation is used.

This means, for instance, that you can define infinitely large data structures, provided that you never use the entire structure. For instance, using imperative-esque pseudo-code, we could create an infinite linked-list containing the number 1 in each position by doing something like:

List makeList()
  List current = new List();
  current.value = 1; = makeList();
  return current;

By looking at this code, we can see what it’s trying to do: it creates a new list, sets its value to 1 and then recursively calls itself to make the rest of the list. Of course, if you actually wrote this code and called it, the program would never terminate, because makeList would keep calling itself ad infinitum.

This is because we assume this imperative-esque language is strict, the opposite of lazy. Strict languages are often referred to as “call by value,” while lazy languages are referred to as “call by name.” In the above pseudo-code, when we “run” makeList on the fifth line, we attempt to get a value out of it. This leads to an infinite loop.

The equivalent code in Haskell is:

makeList = 1 : makeList

This program reads: we’re defining something called makeList (this is what goes on the left-hand side of the equals sign). On the right-hand side, we give the definition of makeList. In Haskell, the colon operator is used to create lists (we’ll talk more about this soon). This right-hand side says that the value of makeList is the element 1 stuck on to the beginning of the value of makeList.

However, since Haskell is lazy (or “call by name”), we do not actually attempt to evaluate what makeList is at this point: we simply remember that if ever in the future we need the second element of makeList, we need to just look at makeList.

Now, if you attempt to write makeList to a file, print it to the screen, or calculate the sum of its elements, the operation won’t terminate because it would have to evaluate an infinitely long list. However, if you simply use a finite portion of the list (say the first 10 10 elements), the fact that the list is infinitely long doesn’t matter. If you only use the first 10 elements, only the first 10 elements are ever calculated. This is laziness.

Second, Haskell is case-sensitive. Many languages are, but Haskell actually uses case to give meaning. Haskell distinguishes between values (for instance, numbers: 1 , 2 , 3 , ...); strings: "abc", "hello", ...; characters: 'a', 'b', ' ', ...; even functions (for instance, the function that squares a value, or the square-root function); and types (the categories to which values belong).

By itself, this is not unusual. Most languages have some system of types. What is unusual is that Haskell requires that the names given to functions and values begin with a lower-case letter and that the names given to types begin with an upper-case letter. The moral is: if your otherwise correct program won’t compile, be sure you haven’t named your function Foo, or something else beginning with a capital letter.

Being a functional language, Haskell eschews side effects. A side effect is essentially something that happens in the course of executing a function that is not related to the output produced by that function.

For instance, in a language like C or Java, you are able to modify “global” variables from within a function. This is a side effect because the modification of this global variable is not related to the output produced by the function. Furthermore, modifying the state of the real world is considered a side effect: printing something to the screen, reading a file, etc., are all side effecting operations.

Functions that do not have side effects are called pure. An easy test for whether or not a function is pure is to ask yourself a simple question: “Does this function’s result depend only on the arguments it receives, and is returning a result the only thing it does?”

All of this means that if you’re used to writing code in an imperative language (like C or Java), you’re going to have to start thinking differently. Most importantly, if you have a value x, you must not think of x as a register, a memory location or anything else of that nature. x is simply a name, just as “Hal” is my name. You cannot arbitrarily decide to store a different person in my name any more than you can arbitrarily decide to store a different value in x. This means that code that might look like the following C code is invalid (and has no counterpart) in Haskell:

int x = 5;
x = x + 1;

A call like x = x + 1 is called destructive update because we are destroying whatever was in x before and replacing it with a new value. Destructive update does not exist in Haskell.

By not allowing destructive updates (or any other such side effecting operations), Haskell code is very easy to comprehend. That is, when we define a function f, and call that function with a particular argument a in the beginning of a program, and then, at the end of the program, again call f with the same argument a, we know we will get out the same result. This is because we know that a cannot have changed and because we know that f only depends on a (for instance, it didn’t increment a global counter). This property is called referential transparency and basically states that if two functions f and g produce the same values for the same arguments, then we may replace f with g (and vice-versa).

Note: There is no agreed-upon exact definition of referential transparency. The definition given above is the one I like best. They all carry the same interpretation; the differences lie in how they are formalized.

Uh! diverso anche il linguaggio, mi piace. Adesso pausa perché sarà lunga 😁


Haskell – 137 – pronti via!

Continuo da qui, copio qui.

Trovo solo qualche dritta, sensata, ne prendo nota ma avanzo, qui.

There are three well known Haskell systems: Hugs, GHC and NHC. Hugs is exclusively an interpreter, meaning that you cannot compile stand-alone programs with it, but can test and debug programs in an interactive environment. GHC is both an interpreter (like Hugs) and a compiler which will produce stand-alone programs. NHC is exclusively a compiler. Which you use is entirely up to you. I’ve tried to make a list of some of the differences in the following list but of course this is far from exhaustive:

  • Hugs – very fast to load files, slow to run them; implements almost all of Haskell 98 (the standard) and most extensions; built-in support for module browsing; cannot create stand-alones; written in C; works on almost every platform; built-in graphics library.
  • GHC – interactive environment is slower than Hugs to load, but allows function definitions in the environment (in Hugs you have to put them in a file); implements all of Haskell 98 and extensions; good support for interfacing with other languages; in a sense the “de facto” standard. It also allows compiled objects to be loaded and tested.
  • NHC – less used and no interactive environment, but produces smaller and often faster executables than does GHC; supports Haskell98 and some extensions.

Se non risulterà necessario non installerò Hugs e NHC. Dipende da come evolverà il tutorial. Finora GHC si è dimostrato OK.

Segue una descrizione dei 3 sistemi. NHC è vuoto, esiste ancora? Pare di no (non c’è nella Wiki). Salto quasi tutto.

Considerazioni sull’editor. Sì Emacs sarebbe meglio ma Medit (quello che uso di solito) va bene per l’highlighting del codice e l’indentazione; per il resto ci sono io.

Insomma, la sto facendo troppo lunga, devo iniziare davvero.


Haskell – 136 – perché sì, perché no

Continuo da qui, copio qui.

Sto ripartendo, con qualche difficoltà al riavvio, ma presto sarò –spero– a regime. Ah! lo sapete che i vecchi di qui dicono “a régime” e “Bèngasi”, ma chissine, scritto non si nota 😋

Perché usare Haskell?
There are many motivations for using Haskell. My personal reason for using Haskell is that I have found that I write more bug-free code in less time using Haskell than any other language. I also find it very readable and extensible.

Perhaps most importantly, however, I have consistently found the Haskell community to be incredibly helpful. The language is constantly evolving (that’s not to say it’s unstable; rather that there are numerous extensions that have been added to some compilers which I find very useful) and user suggestions are often heeded when new extensions are to be implemented.


Perché non usare Haskell?
My two biggest complaints, and the complaints of most Haskellers I know, are:

  • the generated code tends to be slower than equivalent programs written in a language like C; and
  • it tends to be difficult to debug.

The second problem tends not to be a very big issue: most of the code I’ve written is not buggy, as most of the common sources of bugs in other languages simply don’t exist in Haskell. The first issue certainly has come up a few times in my experience; however, CPU time is almost always cheaper than programmer time and if I have to wait a little longer for my results after having saved a few days programming and debugging, that is okay.

C’è Python. Completamente un’altra cosa, non funzionale ( di suo  per design) ma usatissimo (per tutte (quasi) le cose pratiche), con documentazione esemplare. E estensioni e componenti a non finire.

Cosa serve per il tutorial (audience)
Lo scoprirò, se ho capito la sezione, strada facendo. The Haskell language underwent a standardization process and the result is called Haskell 98. The majority of this book will cover the Haskell 98 standard. Any deviations from the standard will be noted (for instance, many compilers offer certain extensions to the standard which are useful; some of these may be discussed).

The goals of this tutorial are:

  • to be practical above all else
  • to provide a comprehensive, free introduction to the Haskell language
  • to point out common pitfalls and their solutions
  • to provide a good sense of how Haskell can be used in the real world

Suona bene, chissà 😋


Haskell – 135 – un altro tutorial

Mica mi arrendo!  Haskell per adesso si sta dimostrando ostico  no, sono io che non ho ancora ingranato. Ma insisto. Anche perché ho trovato un wikibook che promette bene: Yet Another Haskell Tutorial di Hal Daumé III.

Prima ancora di cominciare però una raccomandazione (vale anche per me): il sito del prof merita una deviazione (cit.), è qui. È sul sito dell’Università, ma quel legacy e il fatto che non ne ho trovato di simili mi fa pensare che sia tutto roba sua 👽

OK, ci provo; poi se non va mi arrenderò e torno a un linguaggio sexyassay che sto trascurando da tempo (è una minaccia).

Yet Another Haskell Tutorial
This is an import of Yet Another Haskell Tutorial. Many thanks to Hal Daumé III for permission to use this material. The intention behind this import is to serve as an HTML version of YAHT and as remixable source material for the Haskell wikibook proper. Improvements to both are heartily encouraged.

Uh! c’è tutta una biblioteca lì, si anche una sezione monadi 💥

Insomma vado (come già detto). No, aspetta, esamino brevemente questa intro a Haskell.

Ormai ho un’idea di cosa sia Haskell (pure, lazy e algebricoso), salto a cosa si farà: Our aim in this book is to introduce you to the Haskell programming language – from the very basics to advanced features – and to computer programming in general. We urge seasoned programmers to be especially patient with this process. The languages you are familiar with are likely to differ greatly from Haskell, and the habits acquired from those languages might make it difficult to understand how things work – Haskell is simple, but different. Learning to see the world through the warped mindset of a functional programmer is an adventure in a brave new world, which brings knowledge valuable far beyond the boundaries of any language.

The book is divided into a Beginner’s Track, an Advanced Track, and a section called Haskell in Practice which covers more day-to-day issues and uses mostly items from the Beginner’s Track.

Se ci saranno problemi con Hal tornerò qui, promesso.

Sbirciando avanti vedo che manca qualche parte, chissà 😯 ma ci sono (OK, già detto). Prossimamente inizio (OK, già detto) 👷


Il mio linguaggio favorito

Continuo a essere alla ricerca di tutorial di Haskell, per adesso senza successo.
Cioè ce ne sono tanti ma nessuno è perfetto (cit.). In particolare quando arrivi –se, non tutti ci arrivano– alle monadi risulta che gli esempi esplicativi –indispensabili, a quel punto mi sono perso– don’t run! 😡 C’è qualche funzione deprecata da così tanto tempo da essere stata rimossa o è il modulo che è cambiato, stravolto. Mi viene da fare un paragone fazioso quanto mai ma è la mia storia: quando io ho cominciato venivo katsiato perché il mio codice era diverso da quello dei wheels (OK, nessuno usava questo termine, e chissà se si usa ancora) e poi quella smania del nuovo, il 77. Ebbene sono pochissime le istruzioni che il compilatore rifiuta, anche per il IV (e forse anche prima). Certo il ciclo DO con contatore REAL ma si sapeva che era un’idea balzana; ENCODE e DECODE avevano senso finché mancavano le stringhe. Certo tanta roba nuova, tutta in meglio. Ma tutto compatibile con l’antico. Con Haskell no.

Ma per adesso non dispero, continuo a cercare, anzi ho una pista… 😉

Per intanto faccio cose, vedo gente (cit.) anche se quasi esclusivamente ontehtoobz. Ecco che Twitter mi cinguetta Good programmers don’t have a favorite language psssst basically all programmers have a favorite language. Ottimo tutto il thread.

Non è l’unico, ecco Alexis, lexi_lambda, con uno e due.

Il mio linguaggio preferito? È cambiato nel tempo, dal Fortran (era l’unico che c’era) al Pascal (e derivati, roba di Borland sotto DOS e Windows) a Python e Lisp (vari, in particolare Racket, che a rigore è Scheme). Da non dimenticare i linguaggi di scripting Unix|Linux: shell, AWK, …

Poi ci sarebbero quelli nuovi, ce ne sono di davvero sexy, ho visto Go, Rust, Julia e altri ancora. Fossi giovane mi butterei su Rust, penso però debba ancora crescere. Sono rimasto affascinato da Julia che deve ancora maturare. E lo vedo come alternativo a Python. Quindi…

Oggi Python –è lento mi dicono– è il mio linguaggio.

So benissimo che mancano diversi attori principali: Basic (una volta, usato ma mai considerato mio, probabilmente sbagliando), Java e JavaScript (quest’ultimo vince alla grande in popolarità, non solo sul web), C++ troppo –come dire– quasi come il Common Lisp, anzi di più. Altri ancora usati solo i certi ambiti come MATLAB|Octave.

In questi giorni ho scritto roba in Python, uno script inizialmente previsto in Bash (ehi! per una volta niente compatibilità con Windows) ma poi cresciuto troppo. Beh, viene tutto spontaneo, anche le funzioni meno probabili come la sys.path.insert(). No, non ne ricordavo|conoscevo il nome. Ma c’è nella documentazione. Come c’è la documentazione per i millemila packages che vengono sfornati ogni giorno. Per fortuna quasi tutti evitabili 😉

Essendo il linguaggio molto conosciuto si riesce a lavorare a quattro mani, in remoto (nel mio caso 15 km) dopo aver impostato lo schema (che ha poi subito diverse revisioni).

Ma devo continuare a cercare, voglio diventare funzionale puro. Maybe 😉