I am new to Haskell, I have read blogs on how Haskell code is very elegant. The way I am writing Haskell code, it does not look elegant at all.
Some of the areas I want to improve are
I use case matches on Either values a lot, is using something like
fromRight from Data.Either a better option? I also have some code with nested structures, for right values
case eitherResponse of
Right response -> return $ toJSON $ response
Left msg -> Log $ "Error" <> msg
I have a lot of code which looks like this
fname <- URI.mkPathPiece functionname
kch <- URI.mkPathPiece $ T.pack "channel"
vch <- URI.mkPathPiece channel
kca <- URI.mkPathPiece $ T.pack "chaincode"
vca <- URI.mkPathPiece chaincode
let path = Just (True, Data.List.NonEmpty.fromList [fname, kch, vch, kca, vca])
I really do not like the way it looks, how can I improve this?
Also, Haskell for me is very similar to imperative programming in a "do" block. Is that how Haskell code should look or I am on the wrong track here?
You can improve your second example like this:
pieces <- traverse URI.makePathPiece $
NonEmpty.fromList [functionName, "channel", channel, "chaincode", chaincode]
let path = Just (True, pieces)
We omit the T.packs by using the {-# OverloadedStrings #-} extension. Then use traverse to map a monadic function over a NonEmpty, which is a traversable container.
I need more context to give a concrete alternative to the first example, but if you have nested structures such as:
case eitherResponse of
Left -> some error ...
Right x ->
case someFunction x of
Left -> some error ...
Right y -> ...
This kind of chaining is exactly what Either/ExceptT's Monad instances do. You can make it look like this:
do x <- eitherResponse
y <- someFunction x
Time to learn about monad transformers!
I just can think in improve a little this part with a subfunction kind of helper function:
toJsonOrError (Right response) = return $ toJSON $ response
toJsonOrError (Left msg) = Log $ "Error" <> msg
Also you can import qualified as #Ri- pointed, to replace Data.List.NonEmpty.fromList like:
import qualified Data.List.NonEmpty as NonEmpty (fromList)
to simplify the line:
Just (True, fromList [fname, kch, vch, kca, vca])
The rest of your code is do notation and doesn't look like it can be improved (at leas with the code you've shown)
Related
I want to write a function which, when called, will relentlessly ask for user input until the input can be read as an integer, (at which point the integer is returned to a possible do block where the function was called in the first place)
My code here:
lp_reqInt =
do
input1 <- getLine
if ((readMaybe input1 :: Maybe Int) == Nothing)
then do
putStrLn "(integer input required, please try again)"
lp_reqInt
else let output = fromMaybe (-666) (readMaybe input1 :: Maybe Int)
return output
trying to compile this gives the suspiciously simple error of parse error (possibly incorrect indentation or mismatched brackets) for the last line. (No indent characters were used throughout the whole file)
How should I change my code to have the intended behaviour? Is that even possible?
The other answer discusses what was wrong, and the minimal fix. In addition to the minimal thing that will get you moving on with your code, I thought it might also be interesting to show the idiomatic fix, namely, to use pattern matching instead of if. So:
lp_reqInt :: IO Int
lp_reqInt = do
input1 <- getLine
case readMaybe input1 of
Nothing -> do
putStrLn "(integer input required, please try again)"
lp_reqInt
Just n -> return n
This doesn't require the use of the weird fall-back -666 in fromMaybe, which is nice. Using pattern matching instead of (==) also has a more subtle advantage: it doesn't require the underlying type to have an Eq instance. For Int there is one, so there's no advantage in this code, but in other situations it can matter more. I've also lifted the type signature to the top-level; see here for further discussion of this idiom.
You seem to be slightly misunderstanding how do-notation works.
I'll give you a 'correct' version and we can work off that:
lp_reqInt = do
input1 <- getLine
let maybeInput = readMaybe input1 :: Maybe Int
if maybeInput == Nothing
then do putStrLn "(integer input required, please try again)"
lp_reqInt
else return $ (\(Just x) -> x) maybeInput
Note the let-statement at the top there. I can do a let-statement rather than a let-in-statement here, because it is in the top level of a do-block. When you wrote let output = fromMaybe (...), that was not in the top level of a do-block, that was in the second part of an if-statement, hence it will not work.
You were getting a parse error for this very reason: GHC expected an accompanying in!
Previous answers are great but i just would like to extend this topic with another reasonable approach for those who end up here searching not exactly what the OP is asking for but something relevant.
Since the topic mentions User Input (IO) and Integer (Maybe Int) we end up with a type like IO (Maybe Int). Such types are best expressed under the Monad Transformers, namely MaybeT IO Int and they act nicely as Alternative class members as well.
Haskell has fantastic solutions for these cases such that we may approach the same problem like;
import Control.Monad (msum)
import Control.Monad.Trans.Maybe
import Control.Monad.Trans (lift)
import Text.Read (readMaybe)
lp_reqInt :: MaybeT IO Int
lp_reqInt = msum . repeat $ (lift . putStrLn) "Enter an integer.." >>
(MaybeT $ readMaybe <$> getLine)
It's relentless :)
λ> runMaybeT lp_reqInt
Enter an integer..
boru
Enter an integer..
not an integer
Enter an integer..
42
Just 42
Is it possible to break out of a monad sequence?
For instance, if I want to break out of a sequence earlier based on some condition calculated in the middle of the sequence. Say, in a 'do' notation I bind a value and based on the value I want to either finish the sequence or stop it. Is there something like a 'pass' function?
Thanks.
Directly using if
You could do this directly as Ingo beautifully encapsulated, or equivalently for example
breakOut :: a -> m (Either MyErrorType MyGoodResultType)
breakOut x = do
y <- dosomethingWith x
z <- doSomethingElseWith x y
if isNoGood z then return (Left (someerror z)) else do
w <- process z
v <- munge x y z
u <- fiddleWith w v
return (Right (greatResultsFrom u z))
This is good for simply doing something different based on what values you have.
Using Exceptions in the IO monad
You could use Control.Exception as Michael Litchard correctly pointed out. It has tons of error-handling, control-flow altering stuff in it, and is worth reading if you want to do something complex with this.
This is great if your error production could happen anywhere and your code is complex. You can handle the errors at the top level, or at any level you like. It's very flexible and doesn't mess with your return types. It only works in the IO monad.
import Control.Exception
Really I should roll my own custom type, but I can't be bothered deriving Typable etc, so I'll hack it with the standard error function and a few strings. I feel quite guilty about that.
handleError :: ErrorCall -> IO Int
handleError (ErrorCall msg) = case msg of
"TooBig" -> putStrLn "Error: argument was too big" >> return 10000
"TooSmall" -> putStrLn "Error: argument was too big" >> return 1
"Negative" -> putStrLn "Error: argument was too big" >> return (-1)
"Weird" -> putStrLn "Error: erm, dunno what happened there, sorry." >> return 0
The error handler needs an explicit type to be used in catch. I've flipped the argument to make the do block come last.
exceptOut :: IO Int
exceptOut = flip catch handleError $ do
x <- readLn
if (x < 5) then error "TooSmall" else return ()
y <- readLn
return (50 + x + y)
Monad transformers etc
These are designed to work with any monad, not just IO. They have the same benefits as IO's exceptions, so are officially great, but you need to learn about monad tranformers. Use them if your monad is not IO, and you have complex requirements like I said for Control.Exception.
First, read Gabriel Conzalez's Breaking from a loop for using EitherT to do two different things depending on some condition arising, or MaybeT for just stopping right there in the event of a problem.
If you don't know anything about Monad Transformers, you can start with Martin Grabmüller's Monad Transformers Step by Step. It covers ErrorT. After that read Breaking from a Loop again!
You might also want to read Real World Haskell chapter 19, Error handling.
Call/CC
Continuation Passing Style's callCC is remarkably powerful, but perhaps too powerful, and certainly doesn't produce terribly easy-to-follow code. See this for a fairly positive take, and this for a very negative one.
So what I think you're looking for is the equivalent of return in imperative languages, eg
def do_something
foo
bar
return baz if quux
...
end
Now in haskell this is doesn't work because a monadic chain is just one big function application. We have syntax that makes it look prettier but it could be written as
bind foo (bind bar (bind baz ...)))
and we can't just "stop" applying stuff in the middle. Luckily if you really need it there is an answer from the Cont monad. callCC. This is short for "call with current continuation" and generalizes the notation of returns. If you know Scheme, than this should be familiar.
import Control.Monad.Cont
foo = callCC $ \escape -> do
foo
bar
when baz $ quux >>= escape
...
A runnable example shamelessly stolen from the documentation of Control.Monad.Cont
whatsYourName name =
(`runCont` id) $ do
response <- callCC $ \exit -> do
validateName name exit
return $ "Welcome, " ++ name ++ "!"
return response
validateName name exit = do
when (null name) (exit "You forgot to tell me your name!")
and of course, there is a Cont transformer, ContT (which is absolutely mind bending) that will let you layer this on IO or whatever.
As a sidenote, callCC is a plain old function and completely nonmagical, implementing it is a great challenge
So I suppose there is no way of doing it the way I imagined it originally, which is equivalent of a break function in an imperative loop.
But I still get the same effect below based in Ingo's answer, which is pretty easy (silly me)
doStuff x = if x > 5
then do
t <- getTingFromOutside
doHeavyHalculations t
else return ()
I don't know though how it would work if I need to test 't' in the example above ...
I mean, if I need to test the bound value and make an if decision from there.
You can never break out of a "monad sequence", by definition. Remember that a "monad sequence" is nothing else than one function applied to other values/functions. Even if a "monad sequence" gives you the illusion that you could programme imperative, this is not true (in Haskell)!
The only thing you can do is to return (). This solution of the practical problem has already been named in here. But remember: it gives you only the illusion of being able to break out of the monad!
If I've got a function that returns IO Bool (specifically an atomically), is there any way to use the return value directly in the if statement, without binding?
So currently I've got
ok <- atomically $ do
...
if (ok) then do
...
else do
...
Is it at all possible to write this as something like
if (*some_operator_here* atomically $ do
...) then do
...
else do
...
I was hoping there'd be a way to use something like <- anonymously, i.e., if (<- atomically ...) but so far no such luck.
Similarly on getLine, is it possible to write something like
if ((*operator* getLine) == "1234") then do ...
Related addendum--what is the type of (<-)? I can't get it to show up in ghci. I'm assuming it's m a -> a, but then that would mean it could be used outside of a monad to escape that monad, which would be unsafe, right? Is (<-) not a function at all?
You can use ifM from Control.Conditional if that suits your purpose and its not even hard to write a similar function.
Just to give you example
import Control.Conditional
import Control.Monad
(==:) :: ( Eq a,Monad m) => m a -> m a -> m Bool
(==:) = liftM2 (==)
main = ifM (getLine ==: getLine) (print "hit") (print "miss")
I think there are ways using rebindable syntax extension that you can even use if c then e1 else e2 like syntax for ifM but it is not worth the effort to try that.
With GHC 7.6 and the LambdaCase language extension, you can write
{-# LANGUAGE LambdaCase #-}
import System.Directory
main = do
doesFileExist "/etc/passwd" >>= \case
True -> putStrLn "Yes"
False -> putStrLn "No"
It is not exactly if..then..else, but closer enough, does not require binding to the result, and some people (not me) say that if..then..else is bad style in Haskell anyways.
No, you cannot. Well, to be honest, there is a 'hack' that will allow you to at least write code like this and get it to compile, but the results will almost certainly not be what you wanted or expected.
Why is this not possible? Well, for one thing a value of type IO Bool does not in any sense contain a value of type Bool. Rather it is an 'action' that when performed will return a value of type Bool. For another thing, if this were possible, it would allow you to hide side-effects inside what appears to be pure code. This would violate a core principal of Haskell. And Haskell is very principled.
Is it possible to make those two lines one line:
main = do line <- getLine
let result = words line
what I mean is something like non monadic code
result = words getLine
which -- in my opinion -- would improve readability.
Try this: result <- fmap words getLine
fmap takes a function with a type like a -> b and turns it into f a -> f b for anything that's an instance of Functor, which should include all Monad instances.
There's an equivalent function called liftM that's specific to Monad, for murky historical reasons. You might need to use that instead in some cases, but for standard monads like IO you can stick with fmap.
You can also import Data.Functor or Control.Applicative to get a nice operator version of fmap, so you could write words <$> getLine instead, which often looks prettier.
I am trying to parse an input stream where the first line tells me how many lines of data there are. I'm ending up with the following code, and it works, but I think there is a better way. Is there?
main = do
numCases <- getLine
proc $ read numCases
proc :: Integer -> IO ()
proc numCases
| numCases == 0 = return ()
| otherwise = do
str <- getLine
putStrLn $ findNextPalin str
proc (numCases - 1)
Note: The code solves the Sphere problem https://www.spoj.pl/problems/PALIN/ but I didn't think posting the rest of the code would impact the discussion of what to do here.
Use replicate and sequence_.
main, proc :: IO ()
main = do numCases <- getLine
sequence_ $ replicate (read numCases) proc
proc = do str <- getLine
putStrLn $ findNextPalin str
sequence_ takes a list of actions, and runs them one after the other, in sequence. (Then it throws away the results; if you were interested in the return values from the actions, you'd use sequence.)
replicate n x makes a list of length n, with each element being x. So we use it to build up the list of actions we want to run.
Dave Hinton's answer is correct, but as an aside here's another way of writing the same code:
import Control.Applicative
main = (sequence_ . proc) =<< (read <$> getLine)
proc x = replicate x (putStrLn =<< (findNextPalin <$> getLine))
Just to remind everyone that do blocks aren't necessary! Note that in the above, both =<< and <$> stand in for plain old function application. If you ignore both operators, the code reads exactly the same as similarly-structured pure functions would. I've added some gratuitous parentheses to make things more explicit.
Their purpose is that <$> applies a regular function inside a monad, while =<< does the same but then compresses an extra layer of the monad (e.g., turning IO (IO a) into IO a).
The interesting part of looking at code this way is that you can mostly ignore where the monads and such are; typically there's very few ways to place the "function application" operators to make the types work.
You (and the previous answers) should work harder to divide up the IO from the logic. Make main gather the input and separately (purely, if possible) do the work.
import Control.Monad -- not needed, but cleans some things up
main = do
numCases <- liftM read getLine
lines <- replicateM numCases getLine
let results = map findNextPalin lines
mapM_ putStrLn results
When solving SPOJ problems in Haskell, try not to use standard strings at all. ByteStrings are much faster, and I've found you can usually ignore the number of tests and just run a map over everything but the first line, like so:
{-# OPTIONS_GHC -O2 -optc-O2 #-}
import qualified Data.ByteString.Lazy.Char8 as BS
main :: IO ()
main = do
(l:ls) <- BS.lines `fmap` BS.getContents
mapM_ findNextPalin ls
The SPOJ page in the Haskell Wiki gives a lot of good pointers about how to read Ints from ByteStrings, as well as how to deal with a large quantities of input. It'll help you avoid exceeding the time limit.