Suggestions by @cmdv
Ported from the old book-sources repo:
Chapter 2
Make sure you have npm installed and available on your path.
some might not know what a path is all about. Maybe telling them to check the version $ npm --v or maybe the path itself but not sure this works on all OS's $ which npm
- Computing Diagonals:
does the file still need
module Main where...at the top?
import Math (sqrt)
potentially quickly explaining you can bring in multiple specific operators in the parentheses ie:
import Math (sqrt, pow, min) or the whole lot if left out.
Chapter 3
-
Project Goals: Worth mentioning where to find the repo with example again? It was last mentioned in chapter 1 so might not be obvious anymore.
which is provided by the
purescript-listspackage which can be installed using Bower
I know it's mentioned in previous chapters but iterating how to use Bower might be helpful to those who have zero clue? bower i --save purescript-lists
just like ill-typed values result in type errors, ill-kinded types result in kind errors
Is it worth showing what would not throw a kind error, given previous failing example?
To enter a multi-line declaration in PSCi, we can use multi-line mode, by starting PSCi with the -m (or --multi-line-mode) option.
think I remember there being a new method of switching modes when in PSCi?
> flip (\n s -> show n <> s) "Ten" 10
\ anonymous functions haven't been explained yet
In PureScript, string concatenation uses the diamond operator (<>), instead of the plus operator like in Javascript.
I first read the example code and was confused by the (<>) spent a bit of time trying to work it out and not reading further, then noticing it's explanation was bellow! is it worth putting the explanation after first code example?
we can use the Cons function from Data.List...
I was left confused by what the Cons does maybe giving a little example of it in action might help cons 1 [2, 3, 4] = [1, 2, 3, 4]
I already knew currying but this section left me a bit confused, I wasn't able to see how Currying worked with the address book, is it worth showing a simpler examples first like bellow or there are prob better examples out there 😄 :
add :: Int -> Int -> Int
add = /a -> /b -> a + b
increment :: Int -> Int
increment = add 1
-- calling `add 1` with one value returns a function awaiting another value
-- at this point add looks like: (maybe explain lazy evaluation)
-- add = /1 -> /b -> 1 + b
-- now calling increment with a value
-- increment 2 = 3
-- ad will look like this with the second value called:
-- add = /1 -> /2 -> 1 + 2
addFive :: Int -> Int
addFive = add 5
-- addFive 10 = 15
Chapter 4
1.1 recursion helps to reduce the mutable state in our programs
Maybe a quick explanation of mutable state because if you are coming from OOP this might be an entirely new concept.
1.2
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n - 1)
Potentially break it down a little more to show what is actually happening when the function is recursing. Think this will be a new concept to those not used FP before, maybe something like this:
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n - 1)
-- every time a new _n_ comes into the function 1 is taken away from _n_ and the function is run again until _n_ hits 0 then the recursion stops.
fact 5 = 120
-- (fact 5 * (fact 4 * (fact 3 * (fact 2 *(fact 1 *(fact 1 ))))))
-- (5 * (4 * (3 * (2 * (1 * (1 ))))))
-- 5 * 4 * 3 * 2 * 1 * 1 = 120
else 1 + length (unsafePartial tail arr)
unsafePartial hasn't been explain at this point, I personally don't quite understand it or partial. it comes up again in chapter 6 but I still struggling with why they are used and what each do.
Unsure if this needs to be explained now or later.
infix 8 range as ..
I wasn't sure what 8 was in terms of the higher the number the more it overrides or is it the lower the number? in fact I've forgotten 😂
4.1 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
the pure function threw me a little, so much like Maybe it sort of becomes a wrapper / or imbeds it's results into an Array? Guess a little more clarity as to why it is useful and another good user case for it. When i read pure, I thought that somehow what I'd created was un-pured and needed purifying!
4.2 cartesian product of two arrays
A link or something to a cartesian product, as my non mathematical background I was left stumped 😄 In all honesty I was unable to figure out the exercises without finding some solutions elsewhere, they seemed very mathematically based and you needed to understand the naming to know what it should do or expected output. I also had to just look at JS examples to get what the output should look like.
- Folds:
> foldl (+) 0 (1 .. 5)
unsure if fold needs an example much like in recursion fact or even pointing out that it works like JS reduce? It might not be supper clear how it works inside. It is a little more with the show example. Kind of difficult to show a foldl, maybe:
foldl (\acc n -> acc + n) 0 [1,2,3,4,5] -- 0 being the starting accumulator
foldl (\0 1-> 0 + 1) 0 [2,3,4,5]
foldl (\1 2-> 1 + 2) 0 [3,4,5]
foldl (\3 3-> 3 + 3) 0 [4,5]
foldl (\6 4-> 6 + 4) 0 [5]
foldl (\10 5-> 10 + 5) 0 []
-- array is empty no more recursion 10 + 5 = 15
reverse xs = snoc (reverse (unsafePartial tail xs))
what is snoc? maybe getting reader to check out pursuit or quick explanation
6.1 the reverse example can be written as a fold
maybe another explanation of the inner workings?
reverse :: forall a. Array a -> Array a
reverse = foldr (\x xs -> xs <> [x]) []
reverse [1, 2, 3]
reverse = foldr (\3 [] -> [] <> [3]) [] -- [1, 2]
reverse = foldr (\2 [3] -> [3] <> [2]) [] -- [1]
reverse = foldr (\1 [3, 2] -> [3, 2] <> [1]) [] -- []
-- empty array return what is left [3, 2] <> [1]
[3, 2, 1]
Exercises
I worked through these at the meetup with you and I struggled a fair bit, not sure if they need more hints or a something to get them started then the reader fills in the holes?
Chapter 5
(Medium) Look up Pascal’s Rule for computing binomial coefficients. Use it to write a function which computes binomial coefficients using pattern matching.
was really difficult to find a non mathematical representation of what this meant and made it really hard to understand the exercise.
sortPair :: Array Int -> Array Int
sortPair arr'@[x, y]
| x <= y = arr'
| otherwise = [y, x]
sortPair arr = arr
Would be really good to see a before and after example as it left me puzzled as to how the @ was bing used and the last sortPair case also used arr
sortPair :: Array Int -> Array Int
sortPair [x, y]
| x <= y = [x, y]
| otherwise = [y, x]
sortPair arr = arr
-- above can be converted to use the named pattern
sortPair :: Array Int -> Array Int
sortPair arr'@[x, y]
| x <= y = arr'
| otherwise = [y, x]
sortPair arr = arr
2.1 (Medium) Write a function
fromSingletonwhich uses an array literal pattern to extract the sole member of a singleton array. If the array is not a singleton, your function should return a provided default value. Your function should have typeforall a. a -> Array a -> a
Not sure I understood the question properly and did the bellow code, not even sure that is right.
fromSingleton :: forall a. a -> Array a -> a
fromSingleton _ [x] = x
fromSingleton x _ = x
Here is an example. This function computes "longest zero suffix" of an array (the longest suffix which sums to zero)
took me a little while to understand that what sat between case <here> of was in fact what was being evaluated on each recursion. So in this example:
lzs [1, -1, -2, 3]
-- first iteration
case sum xs of -- sum xs = 1
0 -> xs
_ -> lzs (tail xs) -- tail xs = [-1, -2, 3]
-- Second iteration
case sum xs of -- sum xs = 0
0 -> xs -- xs = [-1, -2, 3]
_ -> lzs (tail xs)
import Partial.Unsafe (unsafePartial)
partialFunction :: Boolean -> Boolean
partialFunction = unsafePartial \true -> true
When I saw the code I didn't have a clue what unsafePartial was is it worth showing a compile error first then an runtime error with the explanation of unsafePartial?
The constructors of an algebraic data type might have the same name as the ADT itself. This is quite common, and it is important not to confuse the
Pointtype constructor with thePointdata constructor - they live in different namespaces.
is this referring to data Point = Point ? I was left a little confused with different namespaces
and uses an infix operator alias
\/to compute the union of the two bounding rectangles.
I ended up trying to find that \/ infix operator on pursuit here but I don't think this is the right operator for it's use here.
6.4 - Computing Bounding Rectangles
class Eq a <= Ord a where
the <= hasn't been explained in that context before, people might think it just means less than or equal to .