I am getting this compile error:
Files.hs:47:17: parse error on input ‘->’
Failed, modules loaded: none.
In the following section of code:
main :: IO ()
main = do
args <- getArgs
let f = case args of
("W":_) -> eoltoW
-- ^ here's 47:17
("U":_) -> eoltoU
_ -> fail "2 - 3 arguments required"
case args of
[_,i,o] -> editWith f i o
[_,i] -> catWith f i
[_] -> fail "2 - 3 arguments required"
While I understand the logic could use some tidying up, I do not see where I am going wrong with case syntax. I figure it might be some weird interaction with do and let, but I can't find any clue as to how to correct it.
Note, I have ensured that I only use spaces for indentation
Edit:
It seems that adding a single space further of indentation (as below) is sufficient to prevent the error, but I am unclear as to why.
main = do
args <- getArgs
let f = case args of
("W":_) -> eoltoW
-- ^ here's 47:17
("U":_) -> eoltoU
_ -> fail "2 - 3 arguments required"
This is described in 2.7 and 10.3. Basically, the rule for let … in a do block* is that all bindings have to be indented the same way:
let a = …
b = …
c = …
Furthermore, the "…" have to be more indented than the layout list. For example, the following is a syntax error:
let a =
10
in a
In order to create a new layout-list, we need to indent it further (see note 1 in section 10.3), which is why
let a =
10
in a
is completely fine. The same holds for your case. All of the cases have to be further indented than f due to the off-side rule.
* that rule actually holds** for more, i.e. for let, where, do and of.
** well, as long as you don't introduce additional braces
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 days ago.
Improve this question
When creating a command-line app, one usually has to do some kind of parsing of command-line arguments, and print an error message if a different number of arguments is expected, or they do not make sense. For the sake of simplicity let's say that a program takes a positive integer as its only argument. Parsing and further program execution in Haskell can be done like this:
main :: IO ()
main = do
args <- getArgs
case args of
[arg] -> case readMaybe arg :: Maybe Int of
Just n | n > 0 -> runProg n
Just n -> die $ "expected a positive integer (got: " <> show n <> ")"
Nothing -> die $ "expected an integer (got: " <> arg <> ")"
_ -> die $ "expected exactly one argument (got: " <> show (length args) <> ")"
Creation of appropriate error message feels clunky to me, especially combined with show anywhere I want to include a non-string argument. There is printf but this on the other hand feels... not Haskell-y. What would be the idiomatic approach here? Perhaps my bias against the methods I listed is unjustified and it is, in fact, idiomatic Haskell?
As per the comment, if you're actually parsing command line arguments, you probably want to use optparse-applicative (or maybe optparse).
More generally, I think a reasonably idiomatic way of constructing complex error messages in Haskell is to represent the errors with an algebraic data type:
data OptError
= BadArgCount Int Int -- expected, actual
| NotInteger String
| NotPositive Int
supply a pretty-printer:
errorMessage :: OptError -> String
errorMessage (BadArgCount exp act) = "expected " <> show exp
<> " arguments, got " <> show act
errorMessage (NotInteger str) = "expected integer, got " <> show str
errorMessage (NotPositive n) = "expected positive integer, got " <> show n
and perform the processing in a monad that supports throwing errors:
data Args = Args Int
processArgs :: [String] -> Either OptError Args
processArgs [x] = case readMaybe x of
Just n | n > 0 -> pure $ Args n
| otherwise -> throwError $ NotPositive n
Nothing -> throwError $ NotInteger x
processArgs xs = throwError $ BadArgCount 1 (length xs)
This is certainly overkill for argument processing in a small command-line utility, but it works well in other contexts that demand complex error reporting, and it has several advantages over the die ... approach:
All the error messages are tabulated in one place, so you know exactly what errors the processArgs function can throw.
Error construction is type checked, reducing the potential for errors in your error handling code.
Error reporting is separated from error rendering. This is useful for internationalization, separate error reporting styles for terminal and non-terminal output, reuse of the functions in driver code that wants to handle errors itself, etc. It's also more ergonomic for development, since you don't have to take a break from "real coding" to make up a sensible error message. This typically results in better error reporting in the final product, since it encourages you to write a clear, consistent set of error messages all at once, after the core logic is finished.
It facilitates refactoring the errors systematically, for example to add location information (not relevant for command line arguments, but relevant for errors in input files, for example), or to add hints/recommendations for correction.
It's relatively easy to define a custom monad that also supports warnings and "non-fatal" errors that allow further error checking to continue, generating a list of errors all at once, instead of failing after the first error.
I haven't used this approach for command line arguments, since I usually use optparse-applicative. But, I have used it when coding up interpreters.
I'm currently working my way through Learn You a Haskell for Great Good, and I'm trying to modify one of the code snippets in chapter nine, "Input and Output" to handle errors correctly:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else
let (Just action) = result
action args
where
dispatch :: [(String, [String] -> IO ())]
is an association list
and
errorExit :: IO ()
is some function that prints an error message.
Compiling this with GHC gives the error message
todo.hs:20:13: parse error in let binding: missing required 'in'
which (to my understanding), seems to be saying that the "let" here doesn't realise it's in a "do" block.
Adding "do" on lines five and seven (after "then" and "else" respectively), changes the error message to
todo.hs:20:13:
The last statement in a 'do' block must be an expression
let (Just action) = result
todo.hs:21:5: Not in scope: `action'.
and now, whilst I agree with the first error message, I also have that one of my variables has jumped out of scope? I've double checked my alignment, and nothing seems to be out of place.
What is the appropriate way to assign a varaible within an if clause that is within a do block?
My suggestion is to not use if in the first place, use case. By using case you get to test the value and bind the result to a variable all in one go. Like this:
main = do
(command:args) <- getArgs
case lookup command dispatch of
Nothing -> errorExit
Just action -> action args
For a more in-depth discussion on why we should prefer case over if see boolean blindness.
#svenningsson suggested the right fix. The reason your original fails is because let clauses can only appear at the top level of a do block - they're simple syntactic sugar that doesn't look into inner expressions:
do let x = 1
y
desugars to the let expression
let x = 1 in y
Alas, in a do block, an expression clause like if ... then ... else ... has no way to declare variables in the rest of the do block at all.
There are at least two possible ways to get around this.
Absorb the remainder of the do block into the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else do
let (Just action) = result
action args
(This is essentially the method #svenningsson uses in his better case version too.)
This can however get a bit awkward if the remainder of the do expression needs to be duplicated into more than one branch.
("Secret" trick: GHC (unlike standard Haskell) doesn't actually require a final, inner do block to be indented more than the outer one, which can help if the amount of indentation starts getting annoying.)
Pull the variable declaration outside the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
action <- if result == Nothing
then
errorExit
else do
let (Just action') = result
return action'
action args
Here that requires making up a new variable name, since the pattern in the let clause isn't just a simple variable.
Finally, action was always out of scope in the last line of your code, but GHC works in several stages, and if it aborts in the parsing stage, it won't check for scope errors. (For some reason it does the The last statement in a 'do' block must be an expression check at a later stage than parsing.)
Addendum: After I understood what #Sibi meant, I see that result == Nothing isn't going to work, so you cannot use if ... then ... else ... with that even with the above workarounds.
You are getting an error because you are trying to compare values of function type. When you perform the check if result == Nothing, it tries to check the equality of Nothing with the value of result which is a type of Maybe ([String] -> IO ()).
So, if you want it to properly typecheck, you have to define Eq instances for -> and that wouldn't make any sense as you are trying to compare two functions for equality.
You can also use fmap to write your code:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
print $ fmap (const args) result
I'm running GHC version 7.8.3 on Windows 7.
Ok, this is not about fancy code snippets. I'm just trying not be a noob here and actually compile something in a way that vaguely resembles the structure of side-effect languages.
I have the following code:
main =
do {
let x = [0..10];
print x
}
I've learned here, that the keyword do is a fancy syntactic sugar for fancy monadic expressions. When I try to compile it, I get the following error:
main.hs:4:1: parse error on input 'print'
And I've learned in this other question, that tabs in Haskell are evil, so I've tried to omit them:
main =
do {
let x = [0..10];
print x
}
And I've failed miserably, because the parse error persists.
I've also learned here, that print is a syntactic sugar for the fancy equivalent:
main =
do {
let x = [0..10];
putStrLn $ show x
}
But then I get this error instead:
main.hs:4:9: parse error on input 'putStrLn'
Trying to face my despair, I've tried to omit the let keyword, after reading this answer:
main =
do {
x = [0..10];
print x
}
And then I get:
main.hs:4:1: parse error on input '='
And in a final useless attempt, I've even tried to omit the ';' like this:
main =
do {
let x = [0..10]
print x
}
And got:
main.hs:4:1: parse error on input 'print'
So,
How to properly use monadic expressions in Haskell without getting parse errors? Is there any hope?
It took me a while to see what was actually going on here:
main =
do {
let x = [0..10];
print x
}
The above looks as if we have a do with two statements, which is perfectly fine. Sure, it is not common practice to use explicit braces-and-semicolons when indentation implicitly inserts them. But they shouldn't hurt... why then the above fails parsing?
The real issue is that let opens a new block! The let block has no braces, so the indentation rule applies. The block starts with the definition x = [0..10]. Then a semicolon is found, which promises that another definition is following e.g.
let x = [0..10] ; y = ...
or even
let x = [0..10] ;
y = ... -- must be indented as the x above, or more indented
However, after the semicolon we find print, which is even indented less than x. According to the indentation rule, this is equivalent to inserting braces like:
main =
do {
let { x = [0..10]; }
print x
}
but the above does not parse. The error message does not refer to the implicitly inserted braces (which would be very confusing!), but only to the next line (nearly as confusing in this case, unfortunately).
The code can be fixed by e.g. providing explicit braces for let:
main = do { let { x = [0..10] };
print x }
Above, indentation is completely irrelevant: you can add line breaks and/or spaces without affecting the parsing (e.g. as in Java, C, etc.). Alternatively, we can move the semicolon below:
main = do { let x = [0..10]
; print x }
The above semicolon is on the next line and is less indented than x, implicitly inserting a } which closes the let block. Here indentation matters, since let uses the indentation rule. If we indent the semicolon more, we can cause the same parse error we found earlier.
Of course, the most idiomatic choice is using the indentation rule for the whole code:
main = do let x = [0..10]
print x
I was about to say, with no useful information, that
main = do
let x = [0..10]
print x
Was working for me, but I'm now off to read about the in within the braces.
As a slight aside, I found http://echo.rsmw.net/n00bfaq.html quite handy for reading about identation/formatting.
main = do let x = [0..10]
print x
works for me
and so does
main = do { let x = [0..10]
in print x }
I think you're trying to mix some different syntax options up.
I have been working on a Haskell project. After producing some lines of code, and when I tried to load the .hs file via ghci, I receive this message, which I do not seem to understand why does it even show.
type Tab = [String]
task :: Tab -> Tab
task t =
let (receiveTab t) = a
(receivePosition t) = b --receivePosition and nextPosition are not really relevant to the context of this question
in nextPosition a b
receiveTab :: Tab -> Tab
receiveTab (h:t)
| elem ' ' h = []
| otherwise = receiveTab t
After attempting to load my .hs file, I receive the message:
task2.hs: Parse error in pattern: receiveTab
It might be a really simple mistake, but my brain can't process what's wrong there, and I can't really afford to just discard the code and start it all over again.
Did you perhaps mean
let a = receiveTab t
b = receivePosition t
Variables (or patterns in general) generally go to the left of the equals sign, values go to the right, as in most other languages.
Summary:
I'm using Cheapskate a library created by John MacFarlane, author of Pandoc, for markdown parsing. I'm running into a type issue that I cannot resolve. Basically I'm trying to generate the html for a code block. I ultimately want renderBlocks def blocks to type check. I cannot get blocks to be of type Blocks
In the source code, the type Blocks is aliased to Seq Block yet my error message says they are different. I've tried laying excessive type annotation throughout without luck. If I specify the type is Blocks as opposed to Seq Block I get an error specifying Blocks as Seq a0.
Here is my project for reference.
The error message:
Couldn't match expected type `Blocks' with actual type `Seq Block'
In the second argument of `renderBlocks', namely `blocks'
In the expression: renderBlocks Cheapskate.def blocks
In the expression:
let
t = T.concat $ map partToText parts
attr
= CodeAttr {codeLang = (T.pack "haskell"), codeInfo = T.empty} ::
CodeAttr
block = CodeBlock attr t
....
in renderBlocks Cheapskate.def blocks
The code:
chunkToHtml :: Chunk -> Markup
chunkToHtml chunk =
case chunk of
Prose str -> toMarkup $ markdown Cheapskate.def (T.pack str)
Def _ _ parts ->
let
t = T.concat $ map partToText parts
attr = CodeAttr { codeLang=(T.pack "haskell"), codeInfo=T.empty} :: CodeAttr
block = CodeBlock attr t
blocks = (singleton block) :: Seq Block
in
renderBlocks Cheapskate.def blocks
Solution was to revert to older containers package from (0.5.5.1) to (0.4.2.1).