2

I want to form a list of Bools for if values suite a Sudoku format. i.e either Nothing or Just x where (1 <= x <= 9). Here is my code below:

import Data.Ix
import Data.Maybe

isSudokuValues :: (Ix a, Num a) => [Maybe a] -> [Bool]
isSudokuValues list = map (maybe True inRange(1, 9).fromJust) list
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Hakim Marley
  • 330
  • 2
  • 5
  • 19
  • 2
    I think its really clear what the function takes in and what it produces. A List of Maybes and returns a list of booleans. Its well visible on the function signature.... – Hakim Marley Oct 09 '15 at 07:51

2 Answers2

3

It is much easier to break out the actual value check to a helper function that works on a single element. That way you can easily see where you unpack the Maybe value

isSudokuValues :: (Ix a, Num a) => [Maybe a] -> [Bool]
isSudokuValues =
  let
    isSudokuValue :: (Ix a, Num a) => Maybe a -> Bool
    isSudokuValue Nothing = True
    isSudokuValue (Just x) = inRange (1, 9) x
  in map isSudokuValue
Emil Vikström
  • 90,431
  • 16
  • 141
  • 175
3

I think you make two errors:

maybe has the following signature:

b -> (a -> b) -> Maybe a -> b

So you should use:

map (maybe True $ inRange (1,9)) list

the fromJust cannot be used, since then maybe would work on a (instead of Maybe a, and furthermore it is one of the tasks of maybe simply to allow safe data processing (such that you don't have to worry about whether the value is Nothing.

Some Haskell users furthermore consider fromJust to be harmfull: there is no guarantee that a value is a Just, so even if you manage to let it work with fromJust, it will error on Nothing, since fromJust cannot handle these. Total programming is one of the things most Haskell programmers aim at.

Demo (with ghci):

Prelude Data.Maybe Data.Ix> (map (maybe True $ inRange (1,9))) [Just 1, Just 15, Just 0, Nothing]
[True,False,False,True]
Prelude Data.Maybe Data.Ix> :t (map (maybe True $ inRange (1,9)))
(map (maybe True $ inRange (1,9))) :: (Num a, Ix a) => [Maybe a] -> [Bool]
Community
  • 1
  • 1
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    Yeah, just dropping `. fromJust` as also a good solution, since `maybe` already does `fromJust`. – Emil Vikström Oct 09 '15 at 07:51
  • @EmilVikström: technically `maybe` doesn't use `fromJust` if I recall, but uses the `(Just x)` in the head as you wrote in your answer. `fromJust` is considered to be harmful by some. – Willem Van Onsem Oct 09 '15 at 07:53
  • i think this wont work because inRange must have the same type as its range of values. I tried this out separately and it worked...inRange(1, 9) $ fromJust $ Just 2.....and got the result of True – Hakim Marley Oct 09 '15 at 08:04
  • 1
    @HakimMarley: Your comment doesn't make much sense: first you say that you think this won't work, the next statement is that you tried it out and it worked. – Willem Van Onsem Oct 09 '15 at 08:06
  • @HakimMarley: I've added a type check, and as you can see, the signature matches with the one you are looking for. This means that `1` and `9` don't *ground* the type to `Integer`, but keep it as generic as possible. – Willem Van Onsem Oct 09 '15 at 08:07
  • 1
    I was missing out the $ sign but its all up and running....this is a much better solution as its just one line and makes work more readable. Thanks man!! – Hakim Marley Oct 09 '15 at 08:12