Body Mass Index program in haskell - haskell

I'm trying to write a simple program in Haskell that can determine someone's body mass index.
Here's what I have written:
type Height = Float
type Weight = Float
type PeopleStats = [(String, Height, Weight)]
and...
bmi :: Height -> Weight -> Float
bmi heightCm weightKg = weightKg/(heightCm)^2
healthy :: Height -> Weight -> Bool
healthy heightCm weightKg | 25 > index && 18 < index = True
| otherwise = False
where index = bmi heightCm weightKg
So far, the function "healthy" can calculate someone's BMI, and the function "healthyPeople" returns a boolean statement determining if the person's BMI falls within the limits which is considered normal for a healthy person.
I want to write a function called "healthyPeople".
healthyPeople :: PeopleStats -> [String]
This function needs to take a list of PeopleStats and returns a list of names (Strings) of people who are deemed to be "healthy" from the "healthy" function.
For example:
If I input [("Lee", 65, 185), ("Wang", 170, 100), ("Tsu", 160, 120)] I will get a list of the names of the people whose BMI returns true form the boolean function in "healthy".
Please help !!!!

First, I think you probably meant to define bmi as:
bmi :: Height -> Weight -> Float
bmi heightCm weightKg = weightKg/(heightCm/100)^2
since the formula uses height in meters.
Now, here's a step by step way to do it using helper functions. I defined a type:
type PersonStats = (String, Height, Weight)
and some functions on that type:
healthyPerson :: PersonStats -> Bool
healthyPerson (name, h, w) = healthy h w
getName :: PersonStats -> String
getName (name, h, w) = name
With those in place, the final function becomes trivial:
healthyPeople :: PeopleStats -> [String]
healthyPeople people = map getName $ filter healthyPerson people
or in point-free notation:
healthyPeople :: PeopleStats -> [String]
healthyPeople = map getName . filter healthyPerson
First you filter out the healthy people from the list, then you map the list of stats into a list of names.
You can express the entire function in one go without the helpers if you use lambdas.

There's a standard Haskell function named filter that does exactly (well, almost) what you want here. It has type (a -> Bool) -> [a] -> [a], i.e., it takes a predicate and a list and returns the members that satisfy the predicate.
You can't apply it directly to PeopleStats because the types don't match up, but it's not hard to write a function to connect the two:
healthyPerson :: (String, Height, Weight) -> Bool
healthyPerson (_, h, w) = healthy h w
healthyPeople :: [(String, Height, Weight)] -> [String]
healthyPeople people = map name $ filter healthyPerson people
where name (s, _, _) = s
This does what you want.

Let's think about what you want to do. You have a list, and you want to (a) select only certain items from the list, and (b) do something to each element of the list. This being Haskell, let's express this in types. The first thing you need—well, it'll have to take a list [a], and a way to check if each element is good. How can it check? Well, it should be a function a -> Bool. And it should give us back a smaller list. In other words, something like [a] -> (a -> Bool) -> [a]. Then we want to take our list and do something to each element. In other words, we'll need a list [a], and a function a -> b. Thus, we'll want something of the type [a] -> (a -> b) -> [b]. Now that we have the types, we're golden: we can use Hoogle to search for them. I highly, highly recommend using Hoogle regularly; it's a Haskell search engine which searches both types—the uniquely awesome part—and function/datatype/typeclass/module/package names. The first function, as it turns out, is the second result for the query: filter :: (a -> Bool) -> [a] -> [a]. This takes a function and a list and returns only the elements of the list for which the function is true. The second function is the first result, map :: (a -> b) -> [a] -> [b], which calls the given function on every element of the given list and returns a list of the results. Note that the arguments have the function, not the list, first; this is more natural, as you'll see shortly.
We want to put these two together for healthyPeople:
healthyPeople :: PeopleStats -> [String]
healthyPeople sts = map (\(n,_,_) -> n) $ filter (\(_,h,w) -> healthy h w) sts
This does what you want. $ is function application, but effectively groups the right-hand side because of its precedence; this allows us to elide parentheses. Here we see why it's nice to have map take its function first; we pass it the name-extracting function ((n,_,_) is a pattern which will match a triple and assign n its first element, ignoring the other two), and then (via $) the filtered list.
This is nice, but not how I'd actually write it. Since sts is the last parameter to the function and to its body, it's unnecessary. In truth, all functions in Haskell take only one argument; this means that if you don't pass enough arguments, you get a function which expects the missing arguments and returns the result. With the help of the function-composition operator ., this gives us
healthyPeople :: PeopleStats -> [String]
healthyPeople = map (\(n,_,_) -> n) . filter (\(_,h,w) -> healthy h w)
And that's probably how I'd write it! You'll find yourself using map and filter a lot; they're real workhorses in functional programming.
There is another idiomatic way you can write healthyPeople; you can use a list comprehension, as follows:
healthyPeople :: PeopleStats -> [String]
healthyPeople stats = [n | (n,h,w) <- stats, healthy h w]
This reads as "construct the list of every n such that (n,h,w) is an element of stats and healthy h w is true. If any of the pattern matches or the predicates fail (you can have more than one of each, though you don't need that here), that element is skipped; otherwise, the left side of the | is executed. It's effectively another way of writing the map/filter version.
Edit 1: As many others are saying, your units are off in bmi; you should have heightCm/100. Also, your healthy function has code equivalent to
f x | cond = True
| otherwise = False
This is equivalent to writing, in a C-like,
bool f(some_type x) {
if (cond)
return true;
else
return false;
}
Instead, you should just write
bool f(some_type x) {
return cond;
}
Or, in this case
f x = cond
This gives you the shorter code
healthy :: Height -> Weight -> Bool
healthy heightCm weightKg = let index = bmi heightCm weightKg
in 25 > index && 18 < index
(You can use a where clause too, but here's a let just because I like it better :))

First off, note that your definition of BMI is incorrect - you need to convert centimetres into metres:
bmi heightCm weightKg = weightKg/(heightCm/100)^2
With that fixed, I came up with the following:
healthyPeople :: PeopleStats -> [String]
healthyPeople [] = []
healthyPeople ((name, height, weight):xs) | healthy height weight = name : healthyPeople xs
| otherwise = healthyPeople xs
This is fairly straight forward. It uses list-based recursion to recurse over all the elements of the list, and it uses guards similarly to how you used them in the healthy function to switch behaviour based on whether the person at the head of the list is healty or not. If they are healthy, their name is concatted with the result of processing the rest of the list.
Next time, you should try solving the problem yourself and then ask for help (and show what you've tried). You'll learn far more!

type Height = Float
type Weight = Float
data PersonStats = PersonStats
{ personName :: String, personHeight :: Height, personWeight :: Weight }
bmi :: Height -> Weight -> Float
bmi heightCm weightKg = weightKg/(heightCm / 100)^2
healthy :: Height -> Weight -> Bool
healthy heightCm weightKg = 25 > index && 18 < index
where index = bmi heightCm weightKg
healthyPerson :: PersonStats -> Bool
healthyPerson p = healthy (personHeight p) (personWeight p)
healthyPeople :: [PersonStats] -> [String]
healthyPeople = map personName . filter healthyPerson

Related

Using data constructor as a function parameter

I am making my way through "Haskell Programming..." and, in Chapter 10, have been working with a toy database. The database is defined as:
data DatabaseItem = DBString String
| DBNumber Integer
| DBDate UTCTime
deriving (Eq, Ord, Show)
and, given a database of the form [databaseItem], I am asked to write a function
dbNumberFilter :: [DatabaseItem] -> [Integer]
that takes a list of DatabaseItems, filters them for DBNumbers, and returns a list the of Integer values stored in them.
I solved that with:
dbNumberFilter db = foldr selectDBNumber [] db
where
selectDBNumber (DBNumber a) b = a : b
selectDBNumber _ b = b
Obviously, I can write an almost identical to extract Strings or UTCTTimes, but I am wondering if there is a way to create a generic filter that can extract a list of Integers, Strings, by passing the filter a chosen data constructor. Something like:
dbGenericFilter :: (a -> DataBaseItem) -> [DatabaseItem] -> [a]
dbGenericFilter DBICon db = foldr selectDBDate [] db
where
selectDBDate (DBICon a) b = a : b
selectDBDate _ b = b
where by passing DBString, DBNumber, or DBDate in the DBICon parameter, will return a list of Strings, Integers, or UTCTimes respectively.
I can't get the above, or any variation of it that I can think of, to work. But is there a way of achieving this effect?
You can't write a function so generic that it just takes a constructor as its first argument and then does what you want. Pattern matches are not first class in Haskell - you can't pass them around as arguments. But there are things you could do to write this more simply.
One approach that isn't really any more generic, but is certainly shorter, is to make use of the fact that a failed pattern match in a list comprehension skips the item:
dbNumberFilter db = [n | DBNumber n <- db]
If you prefer to write something generic, such that dbNUmberFilter = genericFilter x for some x, you can extract the concept of "try to match a DBNumber" into a function:
import Data.Maybe (mapMaybe)
genericFilter :: (DatabaseItem -> Maybe a) -> [DatabaseItem] -> [a]
genericFilter = mapMaybe
dbNumberFilter = genericFilter getNumber
where getNumber (DBNumber n) = Just n
getNumber _ = Nothing
Another somewhat relevant generic thing you could do would be to define the catamorphism for your type, which is a way of abstracting all possible pattern matches for your type into a single function:
dbCata :: (String -> a)
-> (Integer -> a)
-> (UTCTime -> a)
-> DatabaseItem -> a
dbCata s i t (DBString x) = s x
dbCata s i t (DBNumber x) = i x
dbCata s i t (DBDate x) = t x
Then you can write dbNumberFilter with three function arguments instead of a pattern match:
dbNumberFilter :: [DatabaseItem] -> [Integer]
dbNumberFilter = (>>= dbCata mempty pure mempty)

Do notation for monad in function returning a different type

Is there a way to write do notation for a monad in a function which the return type isn't of said monad?
I have a main function doing most of the logic of the code, supplemented by another function which does some calculations for it in the middle. The supplementary function might fail, which is why it is returning a Maybe value. I'm looking to use the do notation for the returned values in the main function. Giving a generic example:
-- does some computation to two Ints which might fail
compute :: Int -> Int -> Maybe Int
-- actual logic
main :: Int -> Int -> Int
main x y = do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
-- does some Int calculation to first, second and third
What I intend is for first, second, and third to have the actual Int values, taken out of the Maybe context, but doing the way above makes Haskell complain about not being able to match types of Maybe Int with Int.
Is there a way to do this? Or am I heading towards the wrong direction?
Pardon me if some terminology is wrongly used, I'm new to Haskell and still trying to wrap my head around everything.
EDIT
main has to return an Int, without being wrapped in Maybe, as there is another part of the code using the result of mainas Int. The results of a single compute might fail, but they should collectively pass (i.e. at least one would pass) in main, and what I'm looking for is a way to use do notation to take them out of Maybe, do some simple Int calculations to them (e.g. possibly treating any Nothing returned as 0), and return the final value as just Int.
Well the signature is in essence wrong. The result should be a Maybe Int:
main :: Int -> Int -> Maybe Int
main x y = do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
return (first + second + third)
For example here we return (first + second + third), and the return will wrap these in a Just data constructor.
This is because your do block, implicitly uses the >>= of the Monad Maybe, which is defined as:
instance Monad Maybe where
Nothing >>=_ = Nothing
(Just x) >>= f = f x
return = Just
So that means that it will indeed "unpack" values out of a Just data constructor, but in case a Nothing comes out of it, then this means that the result of the entire do block will be Nothing.
This is more or less the convenience the Monad Maybe offers: you can make computations as a chain of succesful actions, and in case one of these fails, the result will be Nothing, otherwise it will be Just result.
You can thus not at the end return an Int instead of a Maybe Int, since it is definitely possible - from the perspective of the types - that one or more computations can return a Nothing.
You can however "post" process the result of the do block, if you for example add a "default" value that will be used in case one of the computations is Nothing, like:
import Data.Maybe(fromMaybe)
main :: Int -> Int -> Int
main x y = fromMaybe 0 $ do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
return (first + second + third)
Here in case the do-block thus returns a Nothing, we replace it with 0 (you can of course add another value in the fromMaybe :: a -> Maybe a -> a as a value in case the computation "fails").
If you want to return the first element in a list of Maybes that is Just, then you can use asum :: (Foldable t, Alternative f) => t (f a) -> f a, so then you can write your main like:
-- first non-failing computation
import Data.Foldable(asum)
import Data.Maybe(fromMaybe)
main :: Int -> Int -> Int
main x y = fromMaybe 0 $ asum [
compute x y
compute (x+2) (y+2)
compute (x+4) (y+4)
]
Note that the asum can still contain only Nothings, so you still need to do some post-processing.
Willem's answer is basically perfect, but just to really drive the point home, let's think about what would happen if you could write something that allows you to return an int.
So you have the main function with type Int -> Int -> Int, let's assume an implementation of your compute function as follows:
compute :: Int -> Int -> Maybe Int
compute a 0 = Nothing
compute a b = Just (a `div` b)
Now this is basically a safe version of the integer division function div :: Int -> Int -> Int that returns a Nothing if the divisor is 0.
If you could write a main function as you like that returns an Int, you'd be able to write the following:
unsafe :: Int
unsafe = main 10 (-2)
This would make the second <- compute ... fail and return a Nothing but now you have to interpret your Nothing as a number which is not good. It defeats the whole purpose of using Maybe monad which captures failure safely. You can, of course, give a default value to Nothing as Willem described, but that's not always appropriate.
More generally, when you're inside a do block you should just think inside "the box" that is the monad and don't try to escape. In some cases like Maybe you might be able to do unMaybe with something like fromMaybe or maybe functions, but not in general.
I have two interpretations of your question, so to answer both of them:
Sum the Maybe Int values that are Just n to get an Int
To sum Maybe Ints while throwing out Nothing values, you can use sum with Data.Maybe.catMaybes :: [Maybe a] -> [a] to throw out Nothing values from a list:
sum . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
Get the first Maybe Int value that's Just n as an Int
To get the first non-Nothing value, you can use catMaybes combined with listToMaybe :: [a] -> Maybe a to get Just the first value if there is one or Nothing if there isn't and fromMaybe :: a -> Maybe a -> a to convert Nothing to a default value:
fromMaybe 0 . listToMaybe . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
If you're guaranteed to have at least one succeed, use head instead:
head . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]

Haskell lookup table to return functions

Trying to extend "The Maybe monad" example on this page. Their lookup table phonebook:
phonebook :: [(String, String)]
phonebook = [ ("Bob", "01788 665242"),
("Fred", "01624 556442"),
("Alice", "01889 985333"),
("Jane", "01732 187565") ]
and there chained monad examples:
getRegistrationNumber :: String -- their name
-> Maybe String -- their registration number
getRegistrationNumber name =
lookup name phonebook >>=
(\number -> lookup number governmentalDatabase)
What happens if we want to return a function (that then returns a specific type) instead? So extending from their example, instead of looking up a registration number, we want to lookup lookup either their age, their ZIP, or the years that there property taxes were paid. Given these examples, an INT seems appropriate for the first two, and a List of Ints for the last. FIRST Question: since the lookup table has a type, must all of the return types of the functions be of the same type? I am assuming yes, but am unsure, hence the next question.
lets say that we write these 'finding' functions that return the same type [Int]. Maybe something like these:
getAge :: String -> Maybe [Int]
getAge phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalAgeDatabase)
getZip :: String -> Maybe [Int]
getZip phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalZipCodeDatabase)
getTaxPaidYears :: String -> Maybe [Int]
getTaxPaidYears phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalTaxYearDatabase)
Now, assuming each of the the *Databases return an [Int] type, Second Question How do we write ONE function like lookupPersonsInformation that would return the appropriate information from what's typed in the input String, and given a lookup that returns the appropriate function, returns the information requested? Here is what I am trying to make work:
lookupAppropriateFunction :: [(String, String -> [Int])] --Here I want the second part
-- of the tuple to be the functions
lookupAppropriateFunction = [ ("age", getAge),
("zip", getZip),
("taxes", getTaxPaidYears) ]
lookupPersonsInformation :: String -> Maybe [Int]
lookupPersonsInformation nameAndInfo =
lookup ( words nameAndInfo!!0 ) >>=
( \phoneNumberString -> lookup ( words nameAndInfo!!1 ) lookupAppropriateFunction )
-- >> lookupPersonsInformation "Bob age"
[53] --Bob's age
-- >> lookupPersonsInformation "Fred zip"
[28202] --Fred's age
-- >> lookupPersonsInformation "Alice taxes"
[2010,2011,2013] --Alice's paid taxes years, It looks like she skipped 2012 :)
It is apparent that the errors propagate through to the end as Nothing, but I am unsure how to take the next step in applying this to a higher order function. Is it more in the parsing using words or in the structure of the lookup table that I want to return a function`
I ended up with going with something like the following:
-------------------------------------------------------------------------
intPusher :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and tries to turn it into an Int, and push it onto the stack
intPusher word = case (reads word) of
[] -> \stak -> Nothing
[(x,"")] -> \stak -> Just (x:stak)
[(x,y)] -> \stak -> Nothing
-------------------------------------------------------------------------
dicLookup :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and looks it up in the dictionary
dicLookup word = case (lookup word wordsTable) of
Nothing -> intPusher word
Just f -> f
-------------------------------------------------------------------------
wordsTable :: [(String, Stack -> Maybe Stack)]
-- ^ Checks the string against the commands
wordsTable = [ ("+", addIt)
,("-", subIt)
,("*", multIt)
,("/", divIt)
,("/MOD", modQuotIt)
,("MOD", modIt)
....
,("2DROP", drop2It) ]
-------------------------------------------------------------------------
interpretProgram :: String -> Maybe Stack
interpretProgram str = foldl (>>=) (Just[]) (map dicLookup (words str))
and for each tuple value in the dictionary, I provided the function declaration:
-------------------------------------------------------------------------
addIt :: Stack -> Maybe Stack
-- ^ Adds the first two elements of the stack
addIt stak = case stak of
x:y:xs -> Just (x + y:xs)
x:xs -> Nothing
_ -> Nothing
-------------------------------------------------------------------------
subIt :: Stack -> Maybe Stack
-- ^ Subtracts the first two elements of the stack
subIt stak = case stak of
x:y:xs -> Just (y - x:xs)
x:xs -> Nothing
_ -> Nothing
-------------------------------------------------------------------------
multIt :: Stack -> Maybe Stack
-- ^ Multiplies the first two elements of the stack
multIt stak = case stak of
x:y:xs -> Just (x * y:xs)
x:xs -> Nothing
_ -> Nothing
...
This works by taking a string, breaking it into individual 'words' (if possible, and returning Nothing if it can't) that are then passed into a dictionary to lookup the value of the word compared to the keys in the dictionary, thus acting like a lookup table. If the word is a key in the dictionary, it returns the value, which is a higher order function that does certain tasks (just like the words function, if the higher order function encounters an error, it will return Nothing).
When dealing with Monads, there are only TWO types of return values. Maybe AnyType and Nothing. An AnyType can be any type already declared in the module, or any basic type in Haskell (Int, Char, [Char], etc...). The trick is to return either a Maybe AnyType or a Nothing type. Since Haskell requires terminal declaration for if statements, it can be convention to 'catch' any potential errors and pass along the 'Nothing' type to the final return of a [grand]parent function.

Turtle Graphics as a Haskell Monad

I'm trying to implement turtle graphics in Haskell. The goal is to be able to write a function like this:
draw_something = do
forward 100
right 90
forward 100
...
and then have it produce a list of points (maybe with additional properties):
> draw_something (0,0) 0 -- start at (0,0) facing east (0 degrees)
[(0,0), (0,100), (-100,100), ...]
I have all this working in a 'normal' way, but I've failed to implement it as a Haskell Monad and use the do-notation. The basic code:
data State a = State (a, a) a -- (x,y), angle
deriving (Show, Eq)
initstate :: State Float
initstate = State (0.0,0.0) 0.0
-- constrain angles to 0 to 2*pi
fmod :: Float -> Float
fmod a
| a >= 2*pi = fmod (a-2*pi)
| a < 0 = fmod (a+2*pi)
| otherwise = a
forward :: Float -> State Float -> [State Float]
forward d (State (x,y) angle) = [State (x + d * (sin angle), y + d * (cos angle)) angle]
right :: Float -> State Float -> [State Float]
right d (State pos angle) = [State pos (fmod (angle+d))]
bind :: [State a] -> (State a -> [State a]) -> [State a]
bind xs f = xs ++ (f (head $ reverse xs))
ret :: State a -> [State a]
ret x = [x]
With this I can now write
> [initstate] `bind` (forward 100) `bind` (right (pi/2)) `bind` (forward 100)
[State (0.0,0.0) 0.0,State (0.0,100.0) 0.0,State (0.0,100.0) 1.5707964,State (100.0,99.99999) 1.5707964]
And get the expected result. However I can't make this an instance of Monad.
instance Monad [State] where
...
results in
`State' is not applied to enough type arguments
Expected kind `*', but `State' has kind `* -> *'
In the instance declaration for `Monad [State]'
And if I wrap the list in a new object
data StateList a = StateList [State a]
instance Monad StateList where
return x = StateList [x]
I get
Couldn't match type `a' with `State a'
`a' is a rigid type variable bound by
the type signature for return :: a -> StateList a
at logo.hs:38:9
In the expression: x
In the first argument of `StateList', namely `[x]'
In the expression: StateList [x]
I tried various other versions but I never got it to run as I'd like to. What am I doing wrong? What do I understand incorrectly?
The monad you're devising needs to have two type parameters. One for the saved trail (which will be fixed for a particular do sequence) and other for the results of computations.
You also need to think about how to compose two turtle-monadic values so that the binding operation is associative. For example,
right 90 >> (right 90 >> forward 100)
must be equal to
(right 90 >> right 90) >> forward 100
(and of course similarly for >>= etc.). This means that if you represent the turtle's history by a list of points, the binding operation most likely just cannot append the lists of points together; forward 100 alone will result in something like [(0,0),(100,0)] but when it's prepended with rotation, the saved points need to be rotated too.
I'd say that the simplest approach would be to use the Writer monad. But I wouldn't save the points, I'd save just the actions the turtle performs (so that we don't need to rotate the points when combining the values). Something like
data Action = Rotate Double | Forward Double
type TurtleMonad a = Writer [Action] a
(This also means that we don't need to track the current direction, it's contained in the actions.) Then each of your functions just writes its argument into the Writer. And at the end, you can extract the final list from it and make a simple function that converts all the actions into a list of points:
track :: [Action] -> [(Double,Double)]
Update: Instead of using [Action] it would be better to use Seq from Data.Sequence. It's also a monoid and concatenating two sequences is very fast, it's amortized complexity is O(log(min(n1,n2))), compared to O(n1) of (++). So the improved type would be
type TurtleMonad a = Writer (Seq Action) a

Haskell Map function implementation issues

I just began to learn Haskell and am having trouble with adjusting to the language, for example on the implementation of map more specifically when trying to do similar operations as in the example bellow;
rotate :: Dimensions -> imgBlock -> [(imgBlock,Int)]
rotate d ((p, pix), s, t)
= zip [((p, f pix), s, t) | f <- transformate (fst d)] [0..7]
makeAllRotations :: Dimensions -> [imgBlock] -> [(imgBlock,Int)]
makeAllRotations d ib = map concat (rotate d ib) //Error points Here
Where
type imgBlock = (Block, Int, Int)
type Block = (Pnt, Pxl)
type Dimensions = (Int, Int)
And this is one of the errors i get
asdf.hs:73:30:
Couldn't match expected type `(imgBlock, Int)'
with actual type `[a0]'
Expected type: [[a0]] -> (imgBlock, Int)
Actual type: [[a0]] -> [a0]
In the first argument of `map', namely `concat'
In the expression: map concat (rotate d ib)
I find myself quite frustrated trying to adjust to this new programming 'paradigm' where most of the things I managed to do are through trial and error. I am obviously not understanding map correctly, although i have read the documentation on this website, but all the examples are shown in console like map (2+) [1,2,3] not so much when using them in functions.
Could I get some pointers on where am i going wrong on my map implementation. Thks
The best way to find the problem is to look at the types:
rotate :: Dimensions -> ImgBlock -> [(ImgBlock,Int)]
makeAllRotations :: Dimensions -> [ImgBlock] -> [(ImgBlock,Int)]
map :: (a -> b) -> [a] -> [b]
concat :: [[a]] -> [a]
The map function is trying to call concat on each of the (ImgBlock,Int) pairs in the list returned by rotate. But concat expects to get a nested list as its argument. But the big thing that helped me figure out how to fix it was looking at rotate d ib. The second argument to rotate is ImgBlock, but in that context ib :: [ImgBlock]. You can't pass in a list when a single item is expected. But that's what the map function is for. It allows you to take a function that accepts a single item ('a' in the type signature above) and use that function when you have [a]. I suspect what you want is something like this:
makeAllRotations d ib = concat $ map (rotate d) ib
Because rotate returns a list, map (rotate d) ib returns a list of lists, which fits perfectly as the first argument to the concat function.

Resources