Susan Harkins (406) [Avatar] Offline
#1
Please post errors found in the published version of Get Programming with Haskell here. If necessary, we'll publish a comprehensive list for everyone's convenience. Thank you!

Susan Harkins
Errata Editor
Manning Publications
509898 (4) [Avatar] Offline
#2
In page 361, It is confusig to say "the 2-tuple (,) is not instance of Applicative"

2-tuple (,) is instance of Applicative when the first parameter is instance of Monoid.

instance Monoid a => Applicative ((,) a) where
  pure = (,) empty
  (x, f) <*> (x', y) = (x `mappend` x', f y)


Later, it also says:

Quick check 29.3 Suppose you want to make it so that (pure +) <*> (1,2) <*> (3,4) =
(1+2,1+4,2+3,2+4) = (3,5,5,6). Why doesn’t this work?

QC 29.3 answer This doesn’t work because (3,5,5,6) is an entirely different type than (1,2) or
(3,4). The first is type (a,b,c,d), and the other two are (a,b).

I think the reasoning is not right. The reasons why it does not work are other:

a) kind of (,) is * -> * -> *, and Applicative is * -> *. The first parameter must be set.
b) The first parameter is a number and it is instance of Moniod. But it has two ways of being Moniod: with the sum and with the product and you have to choose which one you want to use.
c) Minor typo: The + operator must appear in brackets.

With these considerations, it does work:

GHCi> pure (+) <*> (Sum 1,2) <*> (Sum 3,4)
(Sum {getSum = 4},6)

GHCi> pure (+) <*> (Product 1,2) <*> (Product 3,4)
(Product {getProduct = 3},6)
509898 (4) [Avatar] Offline
#3
Page 384, solution 30.14 can be simplified:

helloName :: IO ()
helloName = askForName >> getLine >>= putStrLn.nameStatement


Or:

helloName :: IO ()
helloName = askForName >> nameStatement <$> getLine >>= putStrLn


Or:

helloName :: IO ()
helloName = askForName >> getLine >>= return.nameStatement >>= putStrLn


Or:

helloName :: IO ()
helloName = nameStatement <$> (askForName >> getLine) >>= putStrLn
526308 (3) [Avatar] Offline
#4
The current errata itself has typos

1) Page ix:
In the acknowledgements, Vitaly Bragilevski's name is misspelled in one istance.

==> there is one missing letter `n' in the word `instance'

2)
===================================
Page 15

GHCi>simple^2

should be

GHCI>simple 3
===================================

The last line
GHCI>simple 3
should be changed to
GHCI>simple 2

in order to match the following result.



As a reader who bought the book early and loved the book, I really hate the fact that the final version of the book has such a disgusting typo in the very beginning of the book!

This "simple" typo, in my opinion, could destroy many readers' (especially Haskell beginners) interest in the very beginning as well as the author's merit in writing such a great piece.


At least in version 8 that I downloaded in November 2017, I found no such error. And that's why I was enjoying reading this book so much and got to love Haskell. (I really thank the author Will Kurt for writing such a great introduction)

Instead of just publishing an errata, can't the publisher update the file and publish again (now that it is all electronic versions)?

This "simple^2" crazy typo will always be a shame until it is removed from the main text.
dre (42) [Avatar] Offline
#5
WHAT
--------
the function name for 'ifEvenInc' is misspelled; it reads 'ifEveninc'

WHERE
-----------
1. p34 of pdf // section 4.1 // second paragraph
2. p34 of pdf // section 4.1 // last paragraph

FIX
-----
change 'ifEveninc' to 'ifEvenInc' for both occurrences.


dre (42) [Avatar] Offline
#6
WHAT
---------
this sentence doesn't make sense:
"The difference is that the function passed to `filter` must be passed a function that returns True or False"

WHERE
------------
p87 section 9.3 Filtering a list. 1st paragraph

FIX
-----
remove the word "passed", denoted with the square brackets:
"The difference is that the function passed to `filter` must be [passed] a function that returns True or False"
dre (42) [Avatar] Offline
#7
WHAT
--------
2 functions make reference to a variable not appearing in the text. Namely,

1. firstName testPatient => "John"
2. lastName testPatient => "Doe"


WHERE
------------
p122 of pdf. Listing 12.4 in the chapter 12 "Creating Your Own Types", when you're testing your code in GHCi.


FIX
-----
In the text make a reference to testPatient. For example you could do this in Listing 12.4:

GHCi> testPatient = ("John", "Doe")

Yes, with some understanding one could infer that if you were to have some variable called `testPatient` then code in Listing 12.4 would run. But as a noob it would be better to have all necessary code needed to correctly run through the examples present in the book.
dre (42) [Avatar] Offline
#8
WHAT
--------
When you make SixSidedDie an instance of the 'Show' typeclass by writing your own instance definition, no information is given to the reader about having to remove the 'deriving (Show)' code from the 'SixSidedDie' type definition previously written. If you don't do this then your code won't compile.


WHERE
-----------
p144 pdf. 'Implementing Show' section. In the first paragraph no mention is made to the above problem. The Listing 14.3 "Creating an instance of Show for SixSidedDie" code is correct.

FIX
------
Mention that inorder for the Listing 14.3 code to compile you need to revert the type definition for 'SixSidedDie' to what it was defined in Listing 14.1:

data SixSidedDie = S1 | S2 | S3 | S4 | S5 | S6

i.e. remove the "deriving (Show)" code

dre (42) [Avatar] Offline
#9
WHAT
---------
The code for the `rotN` function is wrong. Reference to undefined variable 'n'.



WHERE
-----------
p157 pdf. Section 15.1.2 in Listing 15.2: A generic rotN function to work on any alphabet.


FIX
-----
Change the code from
rotN :: (Bounded a, Enum a) => Int -> a -> a
rotN alphabetSize c = toEnum rotation
    where halfAlphabet = n `div` 2
        offset = fromEnum c + halfAlphabet
        rotation = offset `mod` alphabetSize


to

rotN :: (Bounded a, Enum a) => Int -> a -> a
rotN alphabetSize c = toEnum rotation
    where halfAlphabet = alphabetSize `div` 2
        offset = fromEnum c + halfAlphabet 
        rotation = offset `mod` alphabetSize
dre (42) [Avatar] Offline
#10
WHAT
---------
This sentence does not make sense:

"To solve this, you’ll make sure that you prepend extra False values so that the list is equal to the size of the length of the e converted to bits."


WHERE
-----------
p165 pdf under Section 15.3 Representing values as bits. Its in the last paragraph of Listing 15.15.


FIX
-----
The textbook is trying to explain that the output of intToBits (no apostrophe version) should always be the same length as what you'd get if you converted, to bits, the maxBound value for Int.
For completeness, the length of the output from intToBits should always be 63 ( = length (intToBits' maxBound) ), yes the apostrophe version because we are fixing the length to be this in the intToBits no-apostrophe version.

The sentence should be fixed then to make a reference to this fact:

"To solve this, you’ll make sure that you prepend extra False values to ensure that every bit-list is equal to the size of the bit-list you get when you convert Int's maxBound value."

Maybe some examples would help clarify the point; the reader will then have a concrete idea of the data structure in their imagination.

GHCi> intToBits 2
[False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,
False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,
False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,True,False]

GHCi> intToBits maxBound
[True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,
True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,
True,True,True,True,True,True,True,True,True,True,True,True,True]

All bit-lists are now seen to be the same length of 63.
dre (42) [Avatar] Offline
#11
WHAT
--------
rotEncoder function name is misspelled.

WHERE
-----------
p169 pdf under Section 15.5 A Cipher class. First paragraph. This is the sentence:

"This allows you to create a common interface for any new ciphers you may write, as well as making working with rotEncode and applyOTP easier."


FIX
----
rotEncode should be renamed to rotEncoder
Derek Mahar (24) [Avatar] Offline
#12
In section 1.2 The Glasgow Haskell Compiler, the example that introduces GHC option -o specifies incorrect option parameter helloword which is missing the "l" in "world". So, example

$ghc hello.hs -o helloword
[1 of 1] Compiling Main
Linking helloworld ....


should read

$ghc hello.hs -o helloworld
[1 of 1] Compiling Main
Linking helloworld ....
dre (42) [Avatar] Offline
#13
WHAT
---------
Incorrect sentence when referring to sum types:

"In this example, you can use two type constructors that can either be a FirstName consisting of two Strings or a NameWithMiddle consisting of three Strings."

WHERE
------------
p181 pdf Section 16.2 Sum types -- combining types with "or". Under Listing 16.9, first sentence of first paragraph.


FIX
------
The two data constructors for the 'Name' type are called i) Name ii) NameWithMiddle. There is no data constructor called 'FirstName'. This is what the sentence should say:

"In this example, you can use two type constructors that can either be a Name consisting of two Strings or a NameWithMiddle consisting of three Strings."

dre (42) [Avatar] Offline
#14
WHAT
---------
Spelling mistake in sentence
"But they’ll come up as you dive deeper into the more advanced types classes covered in unit 5 (Functor, Applicative, and Monad)."


WHERE
-----------
p208 pdf 18.2.2 Kinds: types of types. First paragraph, last sentence.


FIX
-----
Change sentence to read:

"But they’ll come up as you dive deeper into the more advanced type classes covered in unit 5 (Functor, Applicative, and Monad)."
dre (42) [Avatar] Offline
#15
WHAT
--------
when investigating the kind of Map.Map you need to import Data.Map using a qualified import. it's needed as so to avoid Prelude name clashes, and is the recommended practice.

more info https://downloads.haskell.org/~ghc/6.12.2/docs/html/libraries/containers-0.3.0.0/Data-Map.html#1

when Data.Map is not imported as recommended in the link, there's an error: Not in scope: type constructor or class 'Map.Map'

BUT. this information about using a qualified import for Data.Map is actually mentioned in the text, albeit in the next section, after the fact.


WHERE
-----------
p209 pdf top of the page. sentence reads:

"In GHCi, you use the :kind command to look up the kinds of any types you’re unsure of
(make sure to import Data.Map):"


FIX
-----
change sentence to:

"In GHCi, you use the :kind command to look up the kinds of any types you’re unsure of
(make sure to import Data.Map using a qualified import, see section 18.2.3):"

OR explicitly:

"In GHCi, you use the :kind command to look up the kinds of any types you’re unsure of
(make sure to import Data.Map like this: import qualified Data.Map as Map):"
dre (42) [Avatar] Offline
#16
WHAT
--------
answer to quick check 18.4 is wrong. the question asked is what's the kind of (,,)?

the answer given is (a,b,c). that's (,,)'s type, not its kind.

WHERE
-----------
p209 pdf Section 18.2.2 Kinds: types of types


FIX
-----
the answer should be :

(,,) :: * -> * -> * -> *
dre (42) [Avatar] Offline
#17
WHAT
--------
spelling mistake. sentence is:

"Maybe is a great example of how powerful types make your code less erro- prone."


WHERE
-----------
p224 in Summary section


FIX
-----
change word to:

"Maybe is a great example of how powerful types make your code less error-prone."
dre (42) [Avatar] Offline
#18
WHAT
--------
missing opening parenthesis in code, line 8 after equals sign

type CompareFunc a = a -> a -> a
type TSCompareFunc a = (Int, Maybe a) -> (Int, Maybe a) -> (Int, Maybe a)
   
makeTSCompare :: Eq a => CompareFunc a -> TSCompareFunc a
makeTSCompare func = newFunc
  where newFunc (i1, Nothing) (i2, Nothing) = (i1, Nothing)
        newFunc (_, Nothing) (i, val) = (i,val)
        newFunc (i, val) (_, Nothing) = i,val)
        newFunc (i1,Just val1) (i2,Just  val2) = if func val1 val2 == val1
                                                 then  (i1, Just val1)
                                                 else  (i2, Just val2)


WHERE
------------
p237 pdf. Listing 20.15 makeTSCompare and useful type synonyms

FIX
-----

type CompareFunc a = a -> a -> a
type TSCompareFunc a = (Int, Maybe a) -> (Int, Maybe a) -> (Int, Maybe a)
   
makeTSCompare :: Eq a => CompareFunc a -> TSCompareFunc a
makeTSCompare func = newFunc
  where newFunc (i1, Nothing) (i2, Nothing) = (i1, Nothing)
        newFunc (_, Nothing) (i, val) = (i,val)
        newFunc (i, val) (_, Nothing) = (i,val)
        newFunc (i1,Just val1) (i2,Just  val2) = if func val1 val2 == val1
                                                 then  (i1, Just val1)
                                                 else  (i2, Just val2)
dre (42) [Avatar] Offline
#19
WHAT
--------
using wrong function for Text types in the following sentence:

"Create your own version of T.lines and T.unlines by using splitOn and T.intercalate."


WHERE
-----------
p278 pdf Quick check 23.3


FIX
-----
change to:

"Create your own version of T.lines and T.unlines by using T.splitOn and T.intercalate."
dre (42) [Avatar] Offline
#20
WHAT
---------
typo for hGetContents function:

"You can see that this code never closes the file handle, and just returns the results of hGetContent."


WHERE
------------
p288 pdf Section 24.3 the trouble with lazy I/O. 2nd last paragraph


FIX
-----

"You can see that this code never closes the file handle, and just returns the results of hGetContents."
dre (42) [Avatar] Offline
#21
WHAT
--------
typo: incorrect type used in listing heading:

"Listing 26.19 MarcDirectoryRaw type synonym and dirEntryLength"

WHERE
-----------
p319 pdf. Listing 26.19


FIX
----
change to be MarcDirectoryEntryRaw:

"Listing 26.19 MarcDirectoryEntryRaw type synonym and dirEntryLength"
dre (42) [Avatar] Offline
#22
WHAT
---------
a type typo


WHERE
-----------
p323 paragraph of text which is above Listing 26.29 Safely looking up a potentially missing subfield.
last sentence of paragraph.


FIX
----
change

"The lookupSubfield function will take a Maybe FieldMetadata argument, the subfield Char, and the MarcRecordRaw, returning a Maybe BC.ByteString of the data inside the subfield."

to

"The lookupSubfield function will take a Maybe FieldMetadata argument, the subfield Char, and the MarcRecordRaw, returning a Maybe T.Text of the data inside the subfield."


( it doesn't make sense to see BC.ByteString. Because as stated in this capstone, we are not to use Data.ByteString.Char8 i.e. BC.ByteString, when dealing with Unicode. )
Steven Leiva (14) [Avatar] Offline
#23
WHAT
---------
Incorrect translation of C code to Haskell code.


WHERE
------------
Pg. 177 of the PDF, Listing 16.2


FIX
------
The Book data type is not a correct translation.

Current Text:

data Book = Author String String Int

Correct Text:

data Book = Book AuthorName String String Int Double
Steven Leiva (14) [Avatar] Offline
#24

WHAT
---------
Incorrect definition of newtype.

"Types defined with newtype can have only one type constructor and one type".


WHERE
------------
Pg. 153 of the PDF, Listing 14.13


FIX
------
Like all types, types defined with newtype can have only one type constructor and one data constructor. The data constructor must have exactly one field.
Steven Leiva (14) [Avatar] Offline
#25
Susan Harkins wrote:You can find a comprehensive errata list at https://manning-content.s3.amazonaws.com/download/6/ef5bf3a-c5e3-489a-9846-e5b08911fef2/Kurt_GetProgrammingwithHaskell_err1_onlyprint.html. Thanks!

Susan Harkins
Errata Editor


Hello Susan - I can't seem to access the link above.
Steven Leiva (14) [Avatar] Offline
#26
WHAT
--------
The word "argument" is used in place of "function"


WHERE
------------
p 348 of the book.


FIX
-----
"In lesson 5, you learned that partial application means that calling a function with fewer arguments that it requires results in a function waiting for the remaining arguments."

GHCi> testPatient = ("John", "Doe")

Yes, with some understanding one could infer that if you were to have some variable called `testPatient` then code in Listing 12.4 would run. But as a noob it would be better to have all necessary code needed to correctly run through the examples present in the book.
dre (42) [Avatar] Offline
#27
Steven Leiva wrote:
Susan Harkins wrote:You can find a comprehensive errata list at https://manning-content.s3.amazonaws.com/download/6/ef5bf3a-c5e3-489a-9846-e5b08911fef2/Kurt_GetProgrammingwithHaskell_err1_onlyprint.html. Thanks!

Susan Harkins
Errata Editor


Hello Susan - I can't seem to access the link above.


that link used to work until a couple of days ago. hopefully they're updating the errata list.
dre (42) [Avatar] Offline
#28
WHAT
---------
typo. parameterized types were introduced in lesson 18, not lesson 15


WHERE
-----------
p342 in the chapter end questions


FIX
-----
change

"Q27.1 When we introduced parameterized types in lesson 15, you used a minimal type Box as the example:"

to

"Q27.1 When we introduced parameterized types in lesson 18, you used a minimal type Box as the example:"
dre (42) [Avatar] Offline
#29
WHAT
--------
sentence is referencing to an incorrect section (section 10.2.2 doesn't exist).


WHERE
-----------
p348 section 28.2 first paragraph


FIX
------
change

"Then in section 10.2.2, you saw that all functions are functions of one argument"

to

"Then in section 11.2.2, you saw that all functions are functions of one argument"

section 11.2.2 is what you want because it talks about functions with multiple arguments and how haskell really only has functions taking one argument.
Steven Leiva (14) [Avatar] Offline
#30
In the book, on Pg. 365, we have the expression totalPrize = (+) doorPrize boxPrize. I think the expression should be totalPrize = pure (+) <*> doorPrize <*> boxPrize.

EDIT: Nevermind, I think the author did this on purpose. It's a bit confusing, but I don't think this is an error.
dre (42) [Avatar] Offline
#31
Steven Leiva wrote:In the book, on Pg. 365, we have the expression totalPrize = (+) doorPrize boxPrize. I think the expression should be totalPrize = pure (+) <*> doorPrize <*> boxPrize.

EDIT: Nevermind, I think the author did this on purpose. It's a bit confusing, but I don't think this is an error.


yes, i agree with you about this being confusing.

while the author demonstrates how the deterministic computation looks, by using the same variable names (doorPrize and boxPrize, which are defined to be lists) it risks confusing the point and thus the reader.

maybe it could read something like:

aSingleDoorPrize :: Int
aSingleDoorPrize = 1000

aSingleBoxPrize :: Int
aSingleBoxPrize = 500

-- the following is a deterministic computation because we have 
-- fixed values for a door prize and a box prize.
totalPrize :: Int
totalPrize = (+) aSingleDoorPrize aSingleBoxPrize
dre (42) [Avatar] Offline
#32
WHAT
--------
in do-notation, the line corresponding to the putStrLn call, is missing the name argument


WHERE
-----------
p389 pdf Figure 31.1Mapping Monad methods to do-notation.

On the righthand side of the figure where it shows the equivalent do-notation correspondence.


FIX
-----
need to change the last line in the do-notation, from this:

"putStrLn nameStatement"

to this

"putStrLn (nameStatement name)"




dre (42) [Avatar] Offline
#33
WHAT
--------
the solution to Q31.1 has an erroneous colon symbol


WHERE
-----------
p583 pdf answers section for Q31.1
writing out the pizza do-notation example using monadic funcs


FIX
-----
everything checks out except for the colon symbol (at the end of line 17 of the following code)

main :: IO ()
main = putStrLn "What is the size of pizza 1" >>
       getLine >>=
       (\size1 ->
         putStrLn "What is the cost of pizza 1" >>
         getLine >>=
         (\cost1 ->
           putStrLn "What is the size of pizza 2" >>
           getLine >>=
           (\size2 ->
             putStrLn "What is the cost of pizza 2" >>
             getLine >>=
             (\cost2 ->
               (\pizza1 ->
                 (\pizza2 ->
                   (\betterPizza ->
                     putStrLn (describePizza betterPizza):
                   ) (comparePizzas pizza1 pizza2)
                 )(read size2,read cost2)
               )(read size1, read cost1)
             )
           )
         )
       )



remove the colon symbol to fix this.
dre (42) [Avatar] Offline
#34
WHAT
--------
typo. missing space between function f, and unit (), for the type signature
of guard.


WHERE
-----------
p406 pdf in "The guard function and the Alternative type class" blue box


FIX
-----

change

"guard :: Alternative f => Bool -> f()"

to

"guard :: Alternative f => Bool -> f ()"

dre (42) [Avatar] Offline
#35
WHAT
---------
sentence doesn't make sense. wording.


WHERE
------------
p412 pdf Section 33.1 Getting started, first paragraph


FIX
-----
this is the original sentence:

"Because you want to see how well you can treat lists such as tables in a relational database, you’ll use an example involving students, teachers, courses, and enrollments"

trying to convey the usuage of lists as tables in a relational database, so maybe change sentence to be:

"Because you want to see how well you can treat lists like tables in a relational database, you’ll use an example involving students, teachers, courses, and enrollments"
dre (42) [Avatar] Offline
#36
WHAT
--------
typo. GradeLevel data type value Sophomore is spelled incorrectly in the students list.


WHERE
-----------
p413 pdf Listing 33.4 A list of example students that you can query


FIX
------

change Sophmore in:

students :: [Student]
students = [(Student 1 Senior (Name "Audre" "Lorde"))
           ,(Student 2 Junior (Name "Leslie" "Silko"))
           ,(Student 3 Freshman (Name "Judith" "Butler"))
           ,(Student 4 Senior (Name "Guy" "Debord"))
           ,(Student 5 Sophmore (Name "Jean" "Baudrillard"))
           ,(Student 6 Junior (Name "Julia" "Kristeva"))]


to Sophomore in:

students :: [Student]
students = [(Student 1 Senior (Name "Audre" "Lorde"))
           ,(Student 2 Junior (Name "Leslie" "Silko"))
           ,(Student 3 Freshman (Name "Judith" "Butler"))
           ,(Student 4 Senior (Name "Guy" "Debord"))
           ,(Student 5 Sophomore (Name "Jean" "Baudrillard"))
           ,(Student 6 Junior (Name "Julia" "Kristeva"))]
Steven Leiva (14) [Avatar] Offline
#37
In Listing 32.2 (pg. 404 of printed book), the variables powerOfTwo and powerOfThree are described as "a single value representing a list...".

I believe that that description is wrong, specifically since on Pg 405, the variables evenValue and oddValue are described the same way, but those variables are bound using the <- operator. The description "a single value representing a list" is more appropriate for evenValue and oddValue
dre (42) [Avatar] Offline
#38
WHAT
---------
typo. missing ) parenthesis in HINQ query


WHERE
------------
p425 pdf Listing 33.23 Queries students and the course they're enrolled in.


FIX
-----
add another closing parenthesis to the 'select' argument to HINQ_ (look at line 3 of code)

change:

studentEnrollmentsQ = HINQ_ 
    (_select (\(st,en) ->
               (studentName st, course en))
    (_join students enrollments studentId student)


to
studentEnrollmentsQ = HINQ_ 
    (_select (\(st,en) ->
               (studentName st, course en)))
    (_join students enrollments studentId student)

dre (42) [Avatar] Offline
#39
WHAT
--------
typos. 2x incorrect command line call when using stack exec


WHERE
-----------
p480 pdf Exending the exercise. The code representing the command line calls for what should be
stack exec primes-exe


FIX
-----
change:

$ stack exe primes-exe
Enter a number to check if it's prime:
4
It is prime!
$ stack exe primes-exe
Enter a number to Factor:
100000000000
Sorry, this number is not a valid candidate for primality testing

to:

$ stack exec primes-exe
Enter a number to check if it's prime:
4
It is prime!
$ stack exec primes-exe
Enter a number to Factor:
100000000000
Sorry, this number is not a valid candidate for primality testing

dre (42) [Avatar] Offline
#40
WHAT
--------
the textbook pdf makes reference to a non-existent stack project.

it references back to lesson 35 which is the palindromes-checker stack project,
not the headache stack project.

there is no headache stack project in the book.



WHERE
------------
p485 pdf. the writing & code situated beneath Listing 38.1 a function that easily causes an error when used but compiles fine.



FIX
-----

(please note the below is not formatted properly, but you get the picture)

change:

As a refresher from lesson 35, open the headaches.cabal file in the projects root directory, find the executable section of the .cabal file, and append -Wall to the list of ghc- options as shown here:
executable headaches-exe
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
build-depends: base
, headaches
default-language: Haskell2010

to:

As a refresher from lesson 35, open the palindrome-checker.cabal file in the projects root directory, find the executable section of the .cabal file, and append -Wall to the list of ghc- options as shown here:

executable palindrome-checker-exe
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
build-depends: base
, text
, palindrome-checker
default-language: Haskell2010
dre (42) [Avatar] Offline
#41
WHAT
--------
the Quick check 38.3 question is incomplete.

this is all it says:

Quick check 38.3 Suppose you have this list:
oddList :: [Maybe Int]
oddList = [Nothing]


WHERE
------------
p491 pdf top of the page


FIX
-----
add the remaining material to the quick check
dre (42) [Avatar] Offline
#42
this error is more serious and occurs in many places in lesson 37 Capstone: building a prime-number library.


WHAT
--------
this has todo with how we handle values greater than the size of our sieve.

here's an example:

- in the isPrime function
- you want to check if the user's input number is greater than the size of our sieve.
- suppose you want to check for primes less than 10. cool. that means our 'primes' list looks like this:

primes = sieve [1 .. 10] -- this is equal to [2,3,5,7]

- but in the 'isPrime' function, when checking if a number exceeds our sieve size we do this:

....
| n >= length primes = Nothing
....

- which evaluates to asking if n >= 4, not 10

compiling and running through some examples illuminates the problem

> isPrime 5
> Nothing

> isPrime 7
> Nothing

.... but we should expect the answers to be Just True for both, because they were
in our sieve, given our max bound of 10.


WHERE
-----------

1. p472 pdf, Listing 37.7 A more robust version of isPrime
2. p474 pdf, Listing 37.10 prop_validPrimesOnly tests that you get Nothing and Just Values
3. p476 pdf, Listing 37.15 Fixing the bug in isPrime
4. p477 pdf, Listing 37.16 Updating your prop_validPrimesOnly after updated isPrime
5. p478 pdf, Listing 37.18 Wrapping unsafePrimeFactors to make it safe


FIX
-----

change all instances of checking the length of primes to getting the last prime:

change

....
| n >= length primes = Nothing
...

to

...
| n >= last primes = Nothing
....

and in the property tests, change

val >= length primes

to

val >= last primes


EDIT: or you could fix it like this

maxN = 10
primes = sieve [1 .. maxN]

and then do

....
| n > maxN = Nothing
....

and

val > maxN
dre (42) [Avatar] Offline
#43
WHAT
--------
function name typo


WHERE
-----------
p503 pdf, top of page, Quick Check 39.2


FIX
------
although there is indeed a valid function called getResponseHeader, going by the answers we want to get the entire header of the response.

so change the function name from:

getResponseHeader

to

getResponseHeaders
dre (42) [Avatar] Offline
#44
WHAT
--------
typo in rawJSON and wrongJSON bytestrings => using an '=' sign where it should be a ':'


WHERE
-----------
in two places:

1. p513 pdf, List 40.7 Taking a JSON representation of your book and converting it to a Book
2. p514 pdf, List 40.8 Parsing JSON that doesn't match your type


FIX
-----
change the bytestring for both the rawJSON variable, and the wrongJSON variable:

in Listing 40.7 change
-----------------------------

...
rawJSON = "{\"author\":\"Emil Ciroan\",\"title\": ?\"A Short History of Decay\",\"year=1949}"
...

to

...
rawJSON = "{\"author\":\"Emil Ciroan\",\"title\": ?\"A Short History of Decay\",\"year:1949}"
...

in Listing 40.8 change
-----------------------------

...
wrongJSON = "{\"writer\":\"Emil Cioran\",\"title\": ?\"A Short History of Decay\",\"year\"=1949}"
...

to

...
wrongJSON = "{\"writer\":\"Emil Cioran\",\"title\": ?\"A Short History of Decay\",\"year\":1949}"
...
dre (42) [Avatar] Offline
#45
WHAT
--------
unwanted line of code in printResults function.

specifically the line to remove is:

print dataName



WHERE
-----------
we are printing out the names of datasets contained in the NOAAResult list

p521 pdf, Listing 40.22 Printing the results


FIX
-----
change this

printResults :: Maybe [NOAAResult] -> IO ()
printResults Nothing = print "error loading data"
printResults (Just results) =  do
    forM_ results (print . name)
      print dataName


to

printResults :: Maybe [NOAAResult] -> IO ()
printResults Nothing = print "error loading data"
printResults (Just results) =  do
    forM_ results (print . name)
dre (42) [Avatar] Offline
#46
WHAT
---------
not sure if this is due to my specific stack settings, but declaring 'datacoverage' as Int in NOAAResult
caused the following error (obtained by using eitherDecode function and looking at the Left value):

"Error in $.results[3].datacoverage: Int is either floating or will cause over or underflow: 0.95"


WHERE
----------
p520 pdf, Listing 40.17 Use NOAAResult type to print the names of the data sets


FIX
------

by changing this

data NOAAResult = NOAAResult
                   { uid :: T.Text
                   , mindate :: T.Text
                   , maxdate :: T.Text
                   , name :: T.Text
                   , datacoverage :: Int
                   , resultId :: T.Text
                   } deriving Show


to this

data NOAAResult = NOAAResult
                   { uid :: T.Text
                   , mindate :: T.Text
                   , maxdate :: T.Text
                   , name :: T.Text
                   , datacoverage :: Double
                   , resultId :: T.Text
                   } deriving Show


data.json is successfully parsed.
dre (42) [Avatar] Offline
#47
WHAT
--------
incorrect formatting for function addUser


WHERE
-----------
p530 pdf Listing 41.8 addUser action connects to database and inserts a user


FIX
-----
change

addUser :: String -> IO ()
addUser userName = do
     conn <- open "tools.db"
     execute conn "INSERT INTO users (username) VALUES (?)"
       (Only userName)
       print "user added"
     close conn


to this

addUser :: String -> IO ()
addUser userName = do
     conn <- open "tools.db"
     execute conn "INSERT INTO users (username) VALUES (?)" (Only userName)
     print "user added"
     close conn
dre (42) [Avatar] Offline
#48
WHAT
--------
typo


WHERE
-----------
p538 pdf, text under Listing 41.18 updateToolTable combines all the steps for updating the tool table


FIX
-------
change

"The final step you have to look at is checking an ite//m back in, which is the case of deleting a row from checkedout."

to

"The final step you have to look at is checking an item back in, which is the case of deleting a row from checkedout."
dre (42) [Avatar] Offline
#49
WHAT
---------
typo function name


WHERE
-----------
p547 pdf middle of page, above Listing 42.3 doubling the values in aLargeList impacts performance



FIX
------
change

"To explore the performance issues of lazy evaluation, let’s look at a modified version of your aLargeList, aLargeArrayList."

to

"To explore the performance issues of lazy evaluation, let’s look at a modified version of your aLargeList, aLargeListDoubled."
dre (42) [Avatar] Offline
#50
WHAT
--------
typo in quick check 42.3


WHERE
-----------
p552 of pdf


FIX
-----
the answer given to the quick check is for tripling the number of beans in each bucket:

accum (*) updateBib $ zip [0 .. 3] $ cycle [3]


but the question asks for

"Try doubling the number of beans in each bucket"

to fix, change to

"Try tripling the number of beans in each bucket"
dre (42) [Avatar] Offline
#51
WHAT
--------
typo function name


WHERE
-----------
p558 pdf. text under Figure 42.3 the bubble sort algorithm


FIX
----
change

"You’ll start with a UArray that you want to sort. You’ll use the listArray function that’s similar to the listToUArry function you wrote, but also takes a pair of bounds as input."

to

"You’ll start with a UArray that you want to sort. You’ll use the listArray function that’s similar to the listToUArray function you wrote, but also takes a pair of bounds as input."
Susan Harkins (406) [Avatar] Offline
#52
An updated errata list for Get Programming with Haskell is available at https://manning-content.s3.amazonaws.com/download/4/699ce32-de8b-4b62-880a-9cbd4a0a4624/Kurt_GetProgrammingwithHaskell_err3.html. Thanks to everyone for your contributions!

Susan Harkins
Errata Editor
Derek Mahar (24) [Avatar] Offline
#53
Line 4 is incorrect in Listing 10.16 Changing the priority of attacks because it assigns a "slow" robot to a "fast" robot. Example

slowRobotRound1 = fight fastRobot slowRobot
fastRobotRound1 = fight slowRobotRound1 fastRobot
slowRobotRound2 = fight fastRobotRound1 slowRobotRound1
fastRobotRound2 = fight fastRobotRound1 slowRobotRound1
slowRobotRound3 = fight fastRobotRound2 slowRobotRound2
fastRobotRound3 = fight slowRobotRound3 fastRobotRound2


produces incorrect result

*Main> printRobot fastRobotRound3
"slowpoke attack:20 hp:0"
*Main> printRobot slowRobotRound3
"slowpoke attack:20 hp:0"


The correct example should read

slowRobotRound1 = fight fastRobot slowRobot
fastRobotRound1 = fight slowRobotRound1 fastRobot
slowRobotRound2 = fight fastRobotRound1 slowRobotRound1
fastRobotRound2 = fight slowRobotRound2 fastRobotRound1
slowRobotRound3 = fight fastRobotRound2 slowRobotRound2
fastRobotRound3 = fight slowRobotRound3 fastRobotRound2


and produce the correct result

*Main> printRobot fastRobotRound3
"speedy attack:15 hp:20"
*Main> printRobot slowRobotRound3
"slowpoke attack:20 hp:-15"


Note that line 4 in the corrected example, the slow robot in round 2 attacks the fast robot from the previous round and assigns it to the same fast robot identifier in round 2.
Derek Mahar (24) [Avatar] Offline
#54
In section 6.3.5 take and drop, replace "then" with "than" in "If you ask for more values then a list has, take gives you what it can, with no error".
Derek Mahar (24) [Avatar] Offline
#55
In Appendix. Answers to end-of-lesson exercises, answer Q2.1 should be the answer to Q2.2, answer Q2.2 should be the answer to the first part of Q2.3, and answer Q2.3 is actually the second part of the answer to Q2.3.
Derek Mahar (24) [Avatar] Offline
#56
In Summary of Lesson 3. Lambda functions and lexical scope, "theoretical corner store" should read "theoretical corner stone".
Derek Mahar (24) [Avatar] Offline
#57
In Q1 of Quickcheck 4.1 in Lesson 4. First-class functions, "it" should not be marked as code.
Derek Mahar (24) [Avatar] Offline
#58
In Lesson 12. Creating your own types, remove dash from sentence "You’ll also learn how to create more-complicated types of your own."
Derek Mahar (24) [Avatar] Offline
#59
In Lesson 13. Type classes, "In this lesson, you're going to look an important abstraction" should read "In this lesson, you're going to look at an important abstraction".
Derek Mahar (24) [Avatar] Offline
#60
In section 13.1. Further exploring types, "to inspect the type of function you find in the wild" should read "to inspect the type of a function you find in the wild".
Derek Mahar (24) [Avatar] Offline
#61
GHCI complains when it interprets SixSidedDie:


administrator@ubuntu:~/projects/haskell$ cat sixSidedDie.hs 
data SixSidedDie = S1 | S2 | S3 | S4 | S5 | S6

instance Show SixSidedDie where
show S1 = "I"
show S2 = "II"
show S3 = "III"
show S4 = "IV"
show S5 = "V"
show S6 = "VI"
administrator@ubuntu:~/projects/haskell$ ghci sixSidedDie.hs 
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( sixSidedDie.hs, interpreted )

sixSidedDie.hs:3:10: warning: [-Wmissing-methods]
    • No explicit implementation for
        either ‘showsPrec’ or ‘Prelude.show’
    • In the instance declaration for ‘Show SixSidedDie’
Ok, modules loaded: Main.


Entering S1 does not return and appears to block indefinitely.

dre wrote:WHAT
--------
When you make SixSidedDie an instance of the 'Show' typeclass by writing your own instance definition, no information is given to the reader about having to remove the 'deriving (Show)' code from the 'SixSidedDie' type definition previously written. If you don't do this then your code won't compile.


WHERE
-----------
p144 pdf. 'Implementing Show' section. In the first paragraph no mention is made to the above problem. The Listing 14.3 "Creating an instance of Show for SixSidedDie" code is correct.

FIX
------
Mention that inorder for the Listing 14.3 code to compile you need to revert the type definition for 'SixSidedDie' to what it was defined in Listing 14.1:

data SixSidedDie = S1 | S2 | S3 | S4 | S5 | S6

i.e. remove the "deriving (Show)" code



Derek Mahar (24) [Avatar] Offline
#62
The cause of the problem is missing indentation in QC 14.1. Unlike the definition of instance Show SixSidedDie in Listing 14.3, QC 14.1 does not indent each show definition. After indenting these definitions, GHCI does not report any errors:

administrator@ubuntu:~/projects/haskell$ cat sixSidedDie.hs 
data SixSidedDie = S1 | S2 | S3 | S4 | S5 | S6

instance Show SixSidedDie where
  show S1 = "I"
  show S2 = "II"
  show S3 = "III"
  show S4 = "IV"
  show S5 = "V"
  show S6 = "VI"
administrator@ubuntu:~/projects/haskell$ ghci sixSidedDie.hs 
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( sixSidedDie.hs, interpreted )
Ok, modules loaded: Main.
*Main> S1
I

Derek Mahar wrote:GHCI complains when it interprets SixSidedDie:


administrator@ubuntu:~/projects/haskell$ cat sixSidedDie.hs 
data SixSidedDie = S1 | S2 | S3 | S4 | S5 | S6

instance Show SixSidedDie where
show S1 = "I"
show S2 = "II"
show S3 = "III"
show S4 = "IV"
show S5 = "V"
show S6 = "VI"
administrator@ubuntu:~/projects/haskell$ ghci sixSidedDie.hs 
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( sixSidedDie.hs, interpreted )

sixSidedDie.hs:3:10: warning: [-Wmissing-methods]
    • No explicit implementation for
        either ‘showsPrec’ or ‘Prelude.show’
    • In the instance declaration for ‘Show SixSidedDie’
Ok, modules loaded: Main.


Entering S1 does not return and appears to block indefinitely.

dre wrote:WHAT
--------
When you make SixSidedDie an instance of the 'Show' typeclass by writing your own instance definition, no information is given to the reader about having to remove the 'deriving (Show)' code from the 'SixSidedDie' type definition previously written. If you don't do this then your code won't compile.


WHERE
-----------
p144 pdf. 'Implementing Show' section. In the first paragraph no mention is made to the above problem. The Listing 14.3 "Creating an instance of Show for SixSidedDie" code is correct.

FIX
------
Mention that inorder for the Listing 14.3 code to compile you need to revert the type definition for 'SixSidedDie' to what it was defined in Listing 14.1:

data SixSidedDie = S1 | S2 | S3 | S4 | S5 | S6

i.e. remove the "deriving (Show)" code



Derek Mahar (24) [Avatar] Offline
#63
In section 14.6, the sentence, "The default behavior when deriving Ord is to use the order that the data constructors are defined," should read, "The default behavior when deriving Ord is to use the order in which the data constructors are defined."
Derek Mahar (24) [Avatar] Offline
#64
In section 15.1.2. The rotN algorithm, in "(you can get this using the same trick with (minBound)", replace "(minBound" with "minBound".
Derek Mahar (24) [Avatar] Offline
#65
In Listing 15.6. Defining a fourLetterEncoder with map, function name fourLetterAlphabetEncoder should be fourLetterEncoder. Listing 15.10. Rotating strings with rotEncoder and rotDecoder repeats this same function name mismatch.
Derek Mahar (24) [Avatar] Offline
#66
In the paragraph that immediately follows Listing 17.7, replace misspelled "mappened" with "mappend" in "Why mappened instead of <>?".
Derek Mahar (24) [Avatar] Offline
#67
In Section 20.2 Stitching together TS data with Semigroup and Monoid, remove the redundant word "them" from the phrase "use them to build them a Map of time/value pairs".
Derek Mahar (24) [Avatar] Offline
#68
In Unit 4. IO in Haskell, "But if you try to do the same thing" should read "But if you try to do the same thing using mystery2".
Derek Mahar (24) [Avatar] Offline
#69
In title, 23.2.1. OverloadedStrings and Haskell extensions, insert a space between "Overloaded" and "Strings" in "OverloadedStrings".
Derek Mahar (24) [Avatar] Offline
#70
In section 24.1. Opening and closing files, replace "stidn" with "stdin" in phrase, "Likewise, getLine is hGetLine where the handle is "stidn"."
Derek Mahar (24) [Avatar] Offline
#71
In the first line of the following example in section 25.1. Working with binary data by using ByteString, replace prefix "BC" in "BC.ByteString" with "B":

B.unpack :: BC.ByteString -> [GHC.Word.Word8]
BC.unpack :: BC.ByteString -> [Char]


The sample source code two listings earlier shows the correct line:

B.unpack :: B.ByteString -> [GHC.Word.Word8]




CrazyCat (3) [Avatar] Online
#72
What indeed!
dre wrote:WHAT
--------

WHERE
-----------
p480 pdf

$ stack exec primes-exe
Enter a number to check if it's prime:
4
It is prime!

Since when is 4 a prime number?
Derek Mahar (24) [Avatar] Offline
#73
In Summary of Lesson 26. Capstone: Processing binary files and book data, replace "fill" with "file" in

- Wrote tools to perform binary fill processing by using ByteString to manipulate bits
Derek Mahar (24) [Avatar] Offline
#74
QC27.1 is only a partially correct answer to question Q27.1. The answer is missing the implementation for morePresents. Here is my complete answer:

data Box a = Box a deriving Show

instance Functor Box where
  fmap func (Box a) = Box (func a)

morePresents :: Int -> Box a -> Box [a]
morePresents count present = fmap (nCopies count) present
  where nCopies count item = (take count . repeat) item


Example results:

GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( boxFunctor.hs, interpreted )
Ok, modules loaded: Main.
*Main> morePresents 5 (Box "gift")
Box ["gift","gift","gift","gift","gift"]
*Main> morePresents 8 (Box '$')
Box "$$$$$$$$"
*Main> morePresents 3 (Box 5)
Box [5,5,5]
Peter Stricker (4) [Avatar] Offline
#75
Page 570, answer to Q11.2:
"an empty list is the same type as the elements of the list"
change to
"an empty list is not the same type as the elements of the list"
Peter Stricker (4) [Avatar] Offline
#76
Page 111
"In lesson 12, you’ll look at type classes"
change to
"In lesson 13, you’ll look at type classes"
136908 (1) [Avatar] Offline
#77
Incorrect Solution to Q17.2
The solution to Q17.2 on page 575 is not right. We should expect <> and mconcat to provide the same answers. Take the following example:

p1 = Probs [0.5, 0.5]
p1 <> p1 = Probs [0.25, 0.25, 0.25, 0.25]

However:
mconcat [p1, p2] 
Probs []


Clearly we do not get the same answer from <> and mconcat. This can be corrected for Probs by defining the instance of Monoid as follows:
instance Monoid Probs where
mappend = (<>)
mempty = Probs [1]


Similar issue for Events. The problem with Events can be corrected by defining the combiner function as follows:
combiner :: String -> String -> String
combiner x y
  | y == mempty = x
  | otherwise = mconcat [x, "-", y]

and change the Monoid instance as:
instance Monoid Events where
  mempty = Events [""]
  mappend = (<>)
286325 (1) [Avatar] Offline
#78
pBook -> Page 403

powerOfTwo n = do 
   value <- [1 :: n]
...

should be
powerOfTwo n = do 
   value <- [1 .. n]
...
Peter Stricker (4) [Avatar] Offline
#79
Page 358, Figure 29.1
fmap :: Functor f :: (a -> b) -> f a -> f b
Change to:
fmap :: Functor f => (a -> b) -> f a -> f b

Same type in all six lines in Figure 29.1