Chapter 4 (roughly first half)
Chapter 4 mentions Arrays a few times and shows Array literals, such as “[1, 2]”. This makes me wonder if Arrays are the main list-like construct (like in JavaScript) or if other links of list-like constructs are more commonly used in PureScript, such as pairs, tuples or linked lists and whether PureScript has literal notations for them too.
Ok, so the notation for calling a function as an infix operator is the same as in Hasekell.
If I want to find out which function implements the computation of an operator, what would be the “standard” way to find out? Do I look it up on Pursuit?
In the medium difficulty exercise, we’re encouraged to experiment in the REPL with setting the precedence level of custom operators.
The problem description mentions PSCi.
I remember that PSCi is a separate command line too. Is this exercise mentioning that CLI tool (directly or indirectly) or is PSCi just the idea of a PureScript REPL? Now I wonder if spago repl
is a compilation step followed by a call to the PSCi command."
I played around a bit, writing expressions in which the custom operator is used next to other operators, to see which precendence level would allow me to write the expressions I want to, without too many parantheses.
I didn’t get very far though, partly because I struggle to understand the type errors given by PureScript compiler and partly because my knowledge of language so narrow that there is not much room for me to experiment.
I ended up thinking that I should understand left- and right-associativity. I read a bit of that on the Wikipedia page, then gave up. In the end, I just copied the precedence declaration from the <$> operator :).
I like this idea. Playing around with concepts is an essential part of learning a new programming language, but I think I would have had more success if given a nudge in the right direction (or a hint of the scope of the problem).
There is a tangential comment “map and concatMap are so fundamental, that they (or rather, their generalizations map and bind)” that made me wonder:
In what sense and how are map
and bind
generalisations of map
and concatMap
? And oddly, is map
a generalisation of map
?
Then in the next paragraph, the book mentions monads (saying “write so-called monad comperhensions”).
Good, I was looking forward to doing IO.
In the same paragraph, “but in this chapter, we will only consider arrays”.
Oh, ok. What, so an array is a monad!?
Then the book shows this code snippet:
$ do
i <- 1 .. n
j <- i .. n
Well ok I still don’t understand it completely but it just looks like a nested for loop.
Then the book says this: “In the last line, we use the pure function. This function can be evaluated in PSCi, but we have to provide a type:”
Is the book saying that there are “typeless” values, that are defined, but do not have a type? How can that be? Can “typeless” values exist in any source file or code context, or only in a special context, like … something to do with monads?
In various code snippets: factors
, factors'
, factors''
and factorsV2
. A passing thought for me, when seeing these binding names was if I should expect to see similar name conventions in other PureScript code.
In the last paragraph of this section, the book says “In the case of arrays, pure simply constructs a singleton array. In fact, we could modify our factors function to use this form, instead of using pure:”
Okay, well now I want to understand pure
. What is it? Something similar to the unit function? Does it do some sort of packing or unpacking of a type? Is it a part of the PureScript language definition or is it something defined in PureScript code, something I could define myself?
The book shows this code snippet.
...
guard $ i * j == n
pure [i, j]
Ok, so pure
and guard
are the same kind of thing. Like, they’re “made of the same stuff”.
After re-reading this sentence in the last paragraph of the section I relised I got stuck on it: “This means that if the guard fails, then the current branch of the array comprehension will terminate early with no results.”
Do we conclude that the “guard has failed” because of what the output is like or do we know that the guard has been given a failed condition because the value “false” was passed to it?
“[…] guard is equivalent to using filter on the intermediate array.” So this “do …” construct is a way to manipulate/transform things? Is guard
different from filter
, but equivalent when guard
is used within a certain construct?
Does guard
return anything other than a length 0 or length 1 array?
Does guard
return the actual value “unit”, wrapped around the monadic array thing or is the meaning of the return value more complex?
How come guard true
returns an error in the REPL but length (guard true)
executes successfully and returns the value “1”.
In this precise moment, I’m wondering if the language should be advertised as appropriate for people with Haskell experience :).
Ok, so it’s difficult to test the individual pieces in REPL. I’ll try a whole block of code with the “do” construct in a source file and make modifications to that to get a feel for things.
Is there any way to just run a source file, without having to setup a spago
project?
Exercise (3) says “[…] and calculates all Pythagorean triples whose components are less than or equal to n […]”. Here, although I sort of guessed it, I wasn’t so sure that the word “components” refers to the values “a”, “b” and “c”.
This meaning could be made more explicit, such as by wording it like this: “each component (a, b and c) is less than or equal to”.
Exercise (4) I sort of enjoyed this exercise but also sort of spent a few hours staring at type errors that I couldn’t understand. There were two main difficulties that I had solving this exercise.
Difficulty (1): The problem definition seems to be inconsistent with the test cases. It seems that the problem description is asking for a list of all possible factorisations of an integer (e.g.: 20 can be 2x2x5 but also 4x5) while the test cases are verifying that the function performs the prime factorisation of the input (which is a different task as the prime factorization is the one that is unique).
The problem description could be made more clear with wording such as the following: "Write a function factorize
which produces the prime factorization of integer n
".
Difficulty (2): My brain kind of insisted that solving this the right way must be done with pattern matching on Maybe things. After some searching on the internet I found out how to pattern match on the Maybe data thing (data value? data type?) but still had to deal with errors such as the following.
Cannot import type Just from module Data.Maybe
It either does not exist or the module does not export it.
Lastly, I think it would more appropriate if the test did not check the order of the prime factors.