Maybe Int to Int from findIndex with Strings - haskell

I've just started with Haskell and have to solve the following task.
I have a list which contains weekdays and I need the index corresponding to the location of the value st if it is found in the list:
weekdays = ["Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","Sonntag"]
findIndex(==st)weekdays
My code works so far, that i get Just 3 for example. However, I read, that this is a Maybe Int and I need just the number out of it.
So, I added a function eliminate:
eliminate :: Maybe Int -> Int
eliminate (Just a) = a
But if I use eliminate findIndex(==st)weekdays it doesn't work and the error is:
*** Expression : eliminate findIndex (flip (==) st) weekdays
*** Term : eliminate
*** Type : Maybe Int -> Int
*** Does not match : a -> b -> c -> d
And I can't figure out a way to go from here, since I'm a beginner.
Can someone help me out? The code has to work on Hugs98 unfortunately.

Note that the type error reported by Hugs relates to associativity and precedence of function application. Your expression
eliminate findIndex (== st) weekdays
attempts to apply eliminate to findIndex first, which is not the intent of your code. I think what you really want to do is:
eliminate (findIndex (== st) weekdays)
or
eliminate $ findIndex (== st) weekdays
These both apply eliminate to the result of findIndex (== st) weekdays. This should type-check as expected.
But, in answer to your question about how to deal with the Maybe value: you can use fromJust or fromMaybe to extract the contained value.
The links go to the current GHC documents but there should be equivalent Hugs functions.
Here's a hint for future use: you can search the Haskell documentation online using Hoogle. The best thing is that you can search both by function name and by type signature. For example, searching by Maybe a -> a would've found both these functions.
Another approach is to pattern-match on Nothing as well as Just a:
eliminate (Just a) = -- Handle a
eliminate Nothing = -- Handle error case
Of course, then you have to decide what eliminate should evaluate to in the error case.

Related

In Haskell, if a function returns a "Maybe a" type just so it is safe and total, how is it useful anymore?

So I have to define a safe version of the head function that would not throw an error when [] is passed as the argument. Here it is:
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
But now, is this function still of any use? Because suppose that type "a" is a Int, then you can add two objects of type Int, but you can't add two objects of type "Maybe Int".
As it was mentioned in comments, you can actually add two Maybes. I just wanted to give another point of view on that.
Yes, you can't directly apply (+) to Maybe Ints, but you can upgrade it to another function that is able to do so automatically.
To upgrade unary function (like (+1)) you write fmap (+1) maybeInt or (+1) <$> maybeInt. If (+1) had type Int -> Int, the fmap (+1) expression has type Maybe Int -> Maybe Int.
Upgrading bin-or-more-ary functions is a bit more complex syntax-wise: (+) <$> maybeInt <*> maybeInt or liftA2 (+) maybeInt maybeInt. Again, here we promote (+) :: Int -> Int -> Int to liftA2 (+) :: Maybe Int -> Maybe Int -> Maybe Int.
Handling Maybes this way allows you to build up a computation that works with Maybes out of pure functions and defer checking for Nothing. Or even avoid that if you eventually plug it into another function that takes Maybe as argument.
Of course, you can use fmap and liftAs on any Applicative, not just Maybe.
"Just" is one such function. Here's how you can use its result (for the ghci REPL):
import Data.Foldable (sequenceA_)
let writeLn = putStrLn . show
let supposedlyUnusable = writeLn <$> Just 0
sequenceA_ supposedlyUnusable
which prints 1 or we can continue to try the other interesting example - using the Nothing case
let supposedlyUnusable = writeLn <$> Nothing
sequenceA_ supposedlyUnusable
which doesn't print anything.
That's a complete program which works even for other instances of Traversable or Foldable where you couldn't do a case analysis on the Maybe value. <$> is the key that lets you apply a function to whatever's contained in the Maybe or any Functor and if you have two Maybes (or two of the same Applicative) you can use the pattern fn <$> applicative_a <*> applicative_b which is like fn a b but where a and b are wrapped up things like Maybe values.
So that leaves a couple of remaining ways to use a Maybe that I can think of, all of which use case analysis:
let {fn (Just n) = Just $ 1 + n; fn Nothing = Nothing}
fn v
-- but that was just a messy way of writing (1+) <$> v
...
let fn v = case v of {Just n -> Just $ 1 + n; Nothing -> Nothing}
-- and that's the same program with a different syntax
...
import Data.Maybe (fromMaybe)
fromMaybe someDefault v
-- and that extracted the `value` from `v` if we had `Just value` or else gave us `someDefault`
...
let {fn (Just n) = writeLn n; fn Nothing = putStrLn "No answer"}
-- this one extracts an action but also provides an action when there's nothing
-- it can be done using <$> and fromMaybe instead, but beginners tend to
-- find it easier because of the tutorials that resulted from the history
-- of the base library's development
let fn v = fromMaybe (putStrLn "No answer") (writeLn <$> v)
oooh, oooh! This one's neato:
import Control.Applicative
let v = Just 0 -- or Nothing, if you want
let errorcase = pure $ putStrLn "No answer"
let successcase = writeLn <$> v
sequenceA_ $ successcase <|> errorcase
-- that uses Alternative in which Maybe tries to give an answer preferring the earliest if it can
of course we also have the classic:
maybe (putStrLn "No answer") writeLn v
Safety comes with a cost. The cost is normally extra code, for avoiding error situations. Haskell has given us the way to avoid this at the compile time rather than at run time.
Let me explain with examples from other languages. Though I won't name any language, but it would be apparent which languages I am talking about. Please be sure that all languages are great in their ways, so do not take this as I am finding fault in other language.
In some languages you have pointers and the way you will do safeHead is to return either int pointer or null pointer. You will have to de-reference pointer to get the value and when you de-reference null pointer you will get error. To avoid this, extra code will be needed to check for null pointer, and do something when it is null.
In some dynamic languages, you have variables assigned to null. So in above example your variable could be type int or it could be null. And what will happen if you add null to int? Most probably undefined situation. Again special handling needs to be done for the null case.
In Haskell too you will have to do the same, you will have to guard the null situation with extra code. So what's the difference? The difference in Haskell is doing it at the compile time and not at the run time.* i.e. the moment you have this kind of code along with your definition of safeHead, p = safeHead xs + safeHead ys, the code will give error at the compile time. You will have to do something more for addition if type Maybe Int. You can write your function for adding two or multiple Maybe Ints or create newype for Maybe Int and overload + or do something as mentioned in other answers.
But whatever you do, you do it before unit testing. Definitely much before it goes on production. And earlier the error is caught lesser is the cost. That's where the advantage of type safe Haskell comes in handy.
* There could be mechanism in other languages to handle this at compile time.

"For all" statements in Haskell

I'm building comfort going through some Haskell toy problems and I've written the following speck of code
multipOf :: [a] -> (Int, a)
multipOf x = (length x, head x)
gmcompress x = (map multipOf).group $ x
which successfully preforms the following operation
gmcompress [1,1,1,1,2,2,2,3] = [(4,1),(3,2),(1,3)]
Now I want this function to instead of telling me that an element of the set had multiplicity 1, to just leave it alone. So to give the result [(4,1),(3,2),3] instead. It be great if there were a way to say (either during or after turning the list into one of pairs) for all elements of multiplicity 1, leave as just an element; else, pair. My initial, naive, thought was to do the following.
multipOf :: [a] -> (Int, a)
multipOf x = if length x = 1 then head x else (length x, head x)
gmcompress x = (map multipOf).group $ x
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
Your diagnosis is right; the then and else must have the same type. There's no "getting past this issue," strictly speaking. Whatever solution you adopt has to use same type in both branches of the conditional. One way would be to design a custom data type that encodes the possibilities that you want, and use that instead. Something like this would work:
-- | A 'Run' of #a# is either 'One' #a# or 'Many' of them (with the number
-- as an argument to the 'Many' constructor).
data Run a = One a | Many Int a
But to tell you the truth, I don't think this would really gain you anything. I'd stick to the (Int, a) encoding rather than going to this Run type.

Parse error in a case statement

I am trying to convert a Maybe Int to an Int in Haskell like this:
convert :: Maybe Int -> Int
convert mx = case mx of
Just x -> x
Nothing -> error "error message"
When I compile it, Haskell tells me: parse error on input 'Nothing'.
I need this, because I want to get the Index of an element in a list with the elem.Index function from the Data.List module and then use this index on the take function. My problem is that elemIndex returns a Maybe Int, but take needs an Int.
This is a whitespace problem. The case clauses need to be indented to the same level.
convert :: Maybe Int -> Int
convert mx = case mx of
Just x -> x
Nothing -> error "error message"
Remember to use only spaces, no tabs.
To add to #leftaroundabout's answer, I think I might provide you with some other options.
First off, you shouldn't make unsafe things like this: your program will fail. It's much cleaner to keep it as a Maybe Int and operate as such, safely. In other words, this was a simple parse error, but making incomplete functions like this may cause far greater problems in the future.
The problem you've encountered it, how can I do that?
We might make a better function, like this:
mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe f m = case m of
Just a -> f a
Nothing -> Nothing
Which would allow you to write:
λ> (+ 15) `mapMaybe` Just 9
Just 24
However, there is a function called fmap, which 'maps' a function over certain data-structures, Maybe included:
λ> (== 32) `fmap` Just 9
Just False
and if you have imported Control.Applicative, there is a nice operator synonym for it:
λ> show <$> Just 9
Just "9"
If you want to know more about these data-structures, called Functors, I would recommend reading Learn-you a Haskell.

Why am I receiving this syntax error - possibly due to bad layout?

I've just started trying to learn haskell and functional programming. I'm trying to write this function that will convert a binary string into its decimal equivalent. Please could someone point out why I am constantly getting the error:
"BinToDecimal.hs":19 - Syntax error in expression (unexpected `}', possibly due to bad layout)
module BinToDecimal where
total :: [Integer]
total = []
binToDecimal :: String -> Integer
binToDecimal a = if (null a) then (sum total)
else if (head a == "0") then binToDecimal (tail a)
else if (head a == "1") then total ++ (2^((length a)-1))
binToDecimal (tail a)
So, total may not be doing what you think it is. total isn't a mutable variable that you're changing, it will always be the empty list []. I think your function should include another parameter for the list you're building up. I would implement this by having binToDecimal call a helper function with the starting case of an empty list, like so:
binToDecimal :: String -> Integer
binToDecimal s = binToDecimal' s []
binToDecimal' :: String -> [Integer] -> Integer
-- implement binToDecimal' here
In addition to what #Sibi has said, I would highly recommend using pattern matching rather than nested if-else. For example, I'd implement the base case of binToDecimal' like so:
binToDecimal' :: String -> [Integer] -> Integer
binToDecimal' "" total = sum total -- when the first argument is the empty string, just sum total. Equivalent to `if (null a) then (sum total)`
-- Include other pattern matching statements here to handle your other if/else cases
If you think it'd be helpful, I can provide the full implementation of this function instead of giving tips.
Ok, let me give you hints to get you started:
You cannot do head a == "0" because "0" is String. Since the type of a is [Char], the type of head a is Char and you have to compare it with an Char. You can solve it using head a == '0'. Note that "0" and '0' are different.
Similarly, rectify your type error in head a == "1"
This won't typecheck: total ++ (2^((length a)-1)) because the type of total is [Integer] and the type of (2^((length a)-1)) is Integer. For the function ++ to typecheck both arguments passed to it should be list of the same type.
You are possible missing an else block at last. (before the code binToDecimal (tail a))
That being said, instead of using nested if else expression, try to use guards as they will increase the readability greatly.
There are many things we can improve here (but no worries, this is perfectly normal in the beginning, there is so much to learn when we start Haskell!!!).
First of all, a string is definitely not an appropriate way to represent a binary, because nothing prevents us to write "éaldkgjasdg" in place of a proper binary. So, the first thing is to define our binary type:
data Binary = Zero | One deriving (Show)
We just say that it can be Zero or One. The deriving (Show) will allow us to have the result displayed when run in GHCI.
In Haskell to solve problem we tend to start with a more general case to dive then in our particular case. The thing we need here is a function with an additional argument which holds the total. Note the use of pattern matching instead of ifs which makes the function easier to read.
binToDecimalAcc :: [Binary] -> Integer -> Integer
binToDecimalAcc [] acc = acc
binToDecimalAcc (Zero:xs) acc = binToDecimalAcc xs acc
binToDecimalAcc (One:xs) acc = binToDecimalAcc xs $ acc + 2^(length xs)
Finally, since we want only to have to pass a single parameter we define or specific function where the acc value is 0:
binToDecimal :: [Binary] -> Integer
binToDecimal binaries = binToDecimalAcc binaries 0
We can run a test in GHCI:
test1 = binToDecimal [One, Zero, One, Zero, One, Zero]
> 42
OK, all fine, but what if you really need to convert a string to a decimal? Then, we need a function able to convert this string to a binary. The problem as seen above is that not all strings are proper binaries. To handle this, we will need to report some sort of error. The solution I will use here is very common in Haskell: it is to use "Maybe". If the string is correct, it will return "Just result" else it will return "Nothing". Let's see that in practice!
The first function we will write is to convert a char to a binary. As discussed above, Nothing represents an error.
charToBinary :: Char -> Maybe Binary
charToBinary '0' = Just Zero
charToBinary '1' = Just One
charToBinary _ = Nothing
Then, we can write a function for a whole string (which is a list of Char). So [Char] is equivalent to String. I used it here to make clearer that we are dealing with a list.
stringToBinary :: [Char] -> Maybe [Binary]
stringToBinary [] = Just []
stringToBinary chars = mapM charToBinary chars
The function mapM is a kind of variation of map which acts on monads (Maybe is actually a monad). To learn about monads I recommend reading Learn You a Haskell for Great Good!
http://learnyouahaskell.com/a-fistful-of-monads
We can notice once more that if there are any errors, Nothing will be returned.
A dedicated function to convert strings holding binaries can now be written.
binStringToDecimal :: [Char] -> Maybe Integer
binStringToDecimal = fmap binToDecimal . stringToBinary
The use of the "." function allow us to define this function as an equality with another function, so we do not need to mention the parameter (point free notation).
The fmap function allow us to run binToDecimal (which expect a [Binary] as argument) on the return of stringToBinary (which is of type "Maybe [Binary]"). Once again, Learn you a Haskell... is a very good reference to learn more about fmap:
http://learnyouahaskell.com/functors-applicative-functors-and-monoids
Now, we can run a second test:
test2 = binStringToDecimal "101010"
> Just 42
And finally, we can test our error handling system with a mistake in the string:
test3 = binStringToDecimal "102010"
> Nothing

Define a haskell function [IO a] -> IO[a]

I am doing a haskell exercise, regarding define a function accumulate :: [IO a] -> IO [a]
which performs a sequence of interactions and accumulates their result in a list.
What makes me confused is how to express a list of IO a ? (action:actions)??
how to write recursive codes using IO??
This is my code, but these exists some problem...
accumulate :: [IO a] -> IO [a]
accumulate (action:actions) = do
value <- action
list <- accumulate (action:actions)
return (convert_to_list value list)
convert_to_list:: Num a =>a -> [a]-> [a]
convert_to_list a [] = a:[]
convert_to_list x xs = x:xs
What you are trying to implement is sequence from Control.Monad.
Just to let you find the answer instead of giving it, try searching for [IO a] -> IO [a] on hoogle (there's a Source link on the right hand side of the page when you've chosen a function).
Try to see in your code what happens when list of actions is empty list and see what does sequence do to take care of that.
There is already such function in Control.Monad and it called sequence (no you shouldn't look at it). You should denote the important decision taken during naming of it. Technically [IO a] says nothing about in which order those Monads should be attached to each other, but name sequence puts a meaning of sequential attaching.
As for the solving you problem. I'd suggest to look more at types and took advice of #sacundim. In GHCi (interpreter from Glasgow Haskell Compiler) there is pretty nice way to check type and thus understand expression (:t (:) will return (:) :: a -> [a] -> [a] which should remind you one of you own function but with less restrictive types).
First of all I'd try to see at what you have showed with more simple example.
data MyWrap a = MyWrap a
accumulate :: [MyWrap a] -> MyWrap [a]
accumulate (action:actions) = MyWrap (convert_to_list value values) where
MyWrap value = action -- use the pattern matching to unwrap value from action
-- other variant is:
-- value = case action of
-- MyWrap x -> x
MyWrap values = accumulate (action:actions)
I've made the same mistake that you did on purpose but with small difference (values is a hint). As you probably already have been told you could try to interpret any of you program by trying to inline appropriate functions definitions. I.e. match definitions on the left side of equality sign (=) and replace it with its right side. In your case you have infinite cycle. Try to solve it on this sample or your and I think you'll understand (btw your problem might be just a typo).
Update: Don't be scary when your program will fall in runtime with message about pattern match. Just think of case when you call your function as accumulate []
Possibly you looking for sequence function that maps [m a] -> m [a]?
So the short version of the answer to your question is, there's (almost) nothing wrong with your code.
First of all, it typechecks:
Prelude> let accumulate (action:actions) = do { value <- action ;
list <- accumulate (action:actions) ; return (value:list) }
Prelude> :t accumulate
accumulate :: (Monad m) => [m t] -> m [t]
Why did I use return (value:list) there? Look at your second function, it's just (:). Calling g
g a [] = a:[]
g a xs = a:xs
is the same as calling (:) with the same arguments. This is what's known as "eta reduction": (\x-> g x) === g (read === as "is equivalent").
So now just one problem remains with your code. You've already taken a value value <- action out of the action, so why do you reuse that action in list <- accumulate (action:actions)? Do you really have to? Right now you have, e.g.,
accumulate [a,b,c] ===
do { v1<-a; ls<-accumulate [a,b,c]; return (v1:ls) } ===
do { v1<-a; v2<-a; ls<-accumulate [a,b,c]; return (v1:v2:ls) } ===
do { v1<-a; v2<-a; v3<-a; ls<-accumulate [a,b,c]; return (v1:v2:v3:ls) } ===
.....
One simple fix and you're there.

Resources