[Haskell-cafe] stuck at the first part of chapter 1 of the CIS course

Richard A. O'Keefe ok at cs.otago.ac.nz
Wed Feb 11 01:11:27 UTC 2015

On 6/02/2015, at 12:19 am, Roelof Wobben <r.wobben at home.nl> wrote:
> it's now looking like this : 
> -- | convert a number to a array in pieces where a negative number will be a empty array. 
> toDigits :: Integer -> [Integer]
> toDigits n 
>   | n < 0 = []
>   | otherwise = n/10 : []

I've seen you thinking the same way in the Erlang mailing list.
Since this can only return a list of one element, it *must* be
wrong.   Also, n / 10 cannot be an integer, but the result is
supposed to be a list of integers.  You need `div` and `mod`,
not / .
You need to think recursively.

Q How can toDigits n ==> [] arise?
A When n is less than or equal to zero.

Q How can toDigits n ==> [d1,d2,...,dm] arise?
A When n is greater than zero, dm is n `mod` 10,
  and [d1,d2,...] without dm at the end is toDigits (n `div` 10).

toDigits n | n <= 0 = []
toDigits n | n > 0  = toDigits (n `div` 10) ++ [n `mod` 10]

There is another solution that builds up the answer from right to
left using a helper function.

In this case, I based an induction on the output I wanted to generate.
Another way to think about it is to *pretend* that the integers are
defined by a data type like

--data Integer
--   = Positive Integer Digit  {- div 10, mod 10 -}
--   | NonPositive

(note the comment signs; this is NOT how integers are defined,
but by using x > 0 -vs- x <= 0 we can tell which case applies
and by using x `div` 10 and x `mod` 10 we can extract the
"components" of an integer.  We are PRETENDING that integers
are a back-to-front list.)

This (pretended) data type is just like a list except that it
branches left
  1234 = Positive (Positive (Positive (Positive NonPositive 1) 2) 3) 4)
instead of right.  Given this view of integers, we can process them
using code that is structurally very much like the recursive code we
would use to process lists.

Just as we would write

f (Positive higher least) = g (f higher) least
f (NonPositive)           = e

so we can write

f n | n >  0 = g (f (n `div` 10)) (n `mod` 10)
f n | n <= 0 = e

GIVEN a schema like that, you just have to ask yourself
"what should e be? what should g be?"

> -- | Main entry point to the application.
> module Main where
> -- | The main entry point.
> main :: IO ()
> main = do
>     toDigits 123 

This makes has to be wrong because toDigits returns a list of integers,
but a list of integers is not an IO action, which is what main needs.
To put it another way, there is nothing in the expression (toDigits 123)
that causes any output to occur.  You probably want something like

main = print (toDigits 1234)

More information about the Haskell-Cafe mailing list