Parse error on input else

if even 2 then 10 else 11 -- works fine if even 2 then let t = 10 else let s = 11 -- _:27: parse error on input 'else' if even 2 then 10 else let s = 11 -- _:34 parse error (possibly incorrect
if even 2 then 10 else 11 -- works fine

if even 2 then let t = 10 else let s = 11 -- _:27: parse error on input 'else'

if even 2 then 10 else let s = 11 -- _:34 parse error (possibly incorrect indentation or mismatched brackets)

because let’s say I want to code something like this with [[p]]:

[ t | let e = [], 
      let o = p!!14, r <- [13,12..1], 
      if even r 
      then 
         let o = zipWith (+) (p!!r) (zipWith max e (drop 1 e))
             t = o
      else 
         e = zipWith (+) (p!!r) (zipWith max o (drop 1 o))
      t = e ]

which at load time reports the error . . . _:33: parse error on input `else’

S.R.I's user avatar

S.R.I

1,86014 silver badges31 bronze badges

asked Jan 9, 2014 at 6:23

user3176181's user avatar

1

You seem to be assigning different values to a binding in different branches in an imperative way. This doesn’t work in Haskell, you must instead of the conditional inside the assignment of the binding like so:

[ t | let e = [],
      let o = p!!14,
      r <- [13,12..1],
      let t = if even r
              then zipWith (+) (p!!r) (zipWith max e (drop 1 e))
              else zipWith (+) (p!!r) (zipWith max o (drop 1 o))
]

Note that the if has to line up. It must either start on the same line as the = or it must be at the same or greater indentation level as the = on the following line.

Another thing I notice is that e will always be [] and I imagine this wasn’t the intention.

answered Jan 10, 2014 at 1:32

David Young's user avatar

David YoungDavid Young

10.7k2 gold badges31 silver badges47 bronze badges

1

The then and the else part in an if expression should return the same type in Haskell.

It’s syntax is like this:

if <condition> then <true-value> else <false-value>

In your example, there is no point of using let unless you are planning to use that variable in the if conditional itself.

LYAH book nicely points out the difference of If conditional as compared to imperative languages:

The difference between Haskell’s if statement and if statements in
imperative languages is that the else part is mandatory in Haskell. In
imperative languages you can just skip a couple of steps if the
condition isn’t satisfied but in Haskell every expression and function
must return something.

answered Jan 9, 2014 at 6:38

Sibi's user avatar

SibiSibi

46.9k16 gold badges95 silver badges159 bronze badges

then 
     let o = zipWith (+) (p!!r) (zipWith max e (drop 1 e))
         t = o

«in» keyword must be after «let» expression

answered Jan 9, 2014 at 11:40

user3177338's user avatar

1

Содержание

  1. Oh, The Kinds of Errors You’ll See
  2. 26 Jul 2018
  3. Oh, The Kinds of Errors You’ll See
  4. Error #1
  5. Top Of File
  6. Fix #1 Order Matters
  7. Error #2
  8. Indentation Rules
  9. Fix #2
  10. Indentation Fixed
  11. Error #3
  12. Functions are Top Level Declarations
  13. Fix #3
  14. Functions at The Top Level
  15. Error #4
  16. Type signatures for functions that exist
  17. Error #5
  18. module Main where
  19. Fix #5 main for Main
  20. Error #6
  21. main :: IO Type
  22. Fix #6 IO & main, together forever
  23. Properly formatted file!
  24. Ошибка синтаксического анализа ошибок Haskell при вводе `= ‘
  25. 4 ответы

Oh, The Kinds of Errors You’ll See

26 Jul 2018

Oh, The Kinds of Errors You’ll See

Haskell has what I would consider to be 3 different types of errors: parse errors, definition errors, & type errors.

Parse errors occur when we have broken a formatting rule or some convention enforced by the compiler.

Once we fix all of those we will get definition errors. Definition errors occur when we are calling that function that isn’t defined by us in our scope or the function hasn’t been imported from another module.

Once we fix all our definition errors we’ll get type errors. Type errors occur when we told the compiler we would do something via our types & we haven’t followed through in our function. After you fix all those errors you’ll get your program to run!

We’re going to step through fixing a file that has various parse errors & then, at the end, have a file that compiles correctly. If you would like to follow along in your own REPL you can find the code here.

Here we have a file that’s breaking some formatting rules. Let’s try compiling this & see what error messages we get.

Error #1

Our first error upon loading the module is a parse error on input module . This error occurred on line 5 of our file. Let’s go look at it.

Top Of File

The rules, for what the top of Haskell files should look, are:

  • Language pragmas are listed at the top of the file
  • Module name is declared above imports & code
  • Imported modules listed before functions

I personally like to have LANGUAGE in all uppercase because I like to yell as much as possible in my code. If you decide to give your file a module name, it must be above the imported modules & functions, with a capitalized name. Then you list modules you would like to import into your file. Imported modules must come before your functions.

Fix #1 Order Matters

Here we’ve moved module Main where above our imported module. Let’s reload to see our next error.

Error #2

The compiler tells us that we have a parse error on input right arrow. It shows us that the error in on line 14. Let’s go check out the code.

The error is on the line that starts with False , line 14. But there are a couple of other problems in the ruleBreaker & lie function too. So keep in mind the where block & the let for the rules we discuss next.

Indentation Rules

For this section, I’m assuming you’re using spaces & using whitespace to denote separation of code blocks. There are warnings by default in Haskell if you use tabs. You can also use curly braces in your code to denote separate blocks. Spaces & whitespace are my preference in Haskell because I think it makes my code look nice. 🙂

  • Code implementations start at least 1 space after the function name on the following line

My most common error is not having enough spaces between my function name & my implementation on the next line. You need to have the implementation 1 space over on the next line compared to the function name. This rule applies for let in expressions, case of expressions, guards, & where blocks!

  • New code blocks inside of other functions must be 1 space over to denote a new block

When you start a new block you need to indent those expressions by at least 1 space. Most people will use at least 2 spaces for readability. So here we can see that we need a new code block because of the use of a case of expression. If you’re using a control structure & the following code will be on a new line that’s a pretty good indication you will need to indent your next section.

  • Code blocks must spatially align

Our True & False here are in the same block because they’re both values our case b of can reduce to. Because these expressions are in the same block we need to make sure that they line up.

Fix #2

Here is our fixed indentation!

Below is our code that wasn’t following our indentation rules.

Indentation Fixed

We fixed all our indentation problems by following the rules we just talked about! Let’s reload the file & see where we’re at with this file now.

Error #3

Parse error. Possibly incorrect indentation. I know what you’re thinking.

You said we fixed all our indentation!

I promise I didn’t lie.

This error occurs on line 19 & we don’t have a line 19 in our file! Let’s go look at the end of the file instead.

Why doesn’t this work? Well, let’s look at the rule.

Functions are Top Level Declarations

let & where are meant to define functions inside other functions to a local scope.

Just a function name at the top level will be fine!

We can’t have anything but functions at the top level of our file. You might be use to declaring things that look like variables using an identifier to distinguish it from functions, but in Haskell everything is a function!

Fix #3

Here is the fixed version of our lie function.

Here is the old version that didn’t compile.

Functions at The Top Level

We got rid of our let here & now let’s recompile.

Error #4

We’ve moved onto definition errors now! We won’t see any more parse errors now! When you get to this stage in your own files you can congratulate yourself on making through 1 stage of the compilation process. 🙂

The type signature for ruleBreaker doesn’t have a function associated with it. Let’s go look at line 10 of our file.

The type signature & the function name are different. You may notice that there is a typo in one of them.

If you have a type signature, you must have a function implementation with it. We’ll just fix our typo.

Type signatures for functions that exist

We fixed our typo & now let’s reload our code!

Error #5

The next error we get here says that the function main isn’t found in our module Main . Let’s look at the code & see if that’s true.

We can see in the code that we have a module Main on line 3 & we don’t have a function called main anywhere in our file. Instead we have a function called mymain .

module Main where

The rule we’re breaking here is that if you use module Main you have to have a function called main . If for whatever reason you don’t want to have a main function, just name your module anything else (that starts with a capital letter).

Fix #5 main for Main

So we will rename mymain to main & reload our code to see how we’re doing.

Error #6

We fixed the definition errors we got & now we’ve gotten some type errors!

Really this is 2 errors, but they go really well hand in hand. The first error says we couldn’t match the expected type of main , which is IO of something, with the actual type, in the type signature, Int . The compiler tells us on the 2nd error that we told them we would give them an Int , but we are actually providing an IO () . It points to line 8, specifically at the expression: print «hello world» . This is expected because print has the type is a to IO () where a has the constraint to have an instance of Show . Let’s go look at those lines.

We did in fact say we would return an Int here & we aren’t doing it.

main :: IO Type

main always returns IO of some type. Usually main gives us back a value of IO ()

In our main function we use print . print has the type a to IO () . So we know we’ll want to return IO () .

The rule for using the function main is that main must return IO of some type. It doesn’t have to be IO () , but print has the return type of IO () . Let’s change our type signature of main to IO () .

Fix #6 IO & main, together forever

Here we are, main has the type IO () , which reflects the type that print «hello world» gives us. Let’s reload.

Sweet! Our file is properly formatted now! There are no more errors in our code & this will run fine. So… just one more thing. 🙂

Properly formatted file!

Let’s change the strings to reflect that our code compiles haha.

If you notice any issues with this post please submit an issue here. If this was easy for you to follow along with please consider adding to the Haskell wiki on compiler errors.

Источник

Ошибка синтаксического анализа ошибок Haskell при вводе `= ‘

Я новичок в Haskell, и после запуска ghci Я пытался:

чего я не понимаю.

Как ни странно, раньше это работало хорошо. Я полагаю, что я неправильно сконфигурировал Haskell. Переустановка ghc6 не решает проблемы.

Для информации я использую Ubuntu 10.4, а версия ghc6 — 6.12.1-12.

задан 31 мая ’11, 05:05

4 ответы

В GHCi 7.x или ниже вам понадобится let определять вещи в нем.

Начиная с GHC 8.0.1, привязки верхнего уровня поддерживаются в GHCi, поэтому код OP будет работать без изменений.

Спасибо. «Real world haskell» (по крайней мере, в моей версии) не имеет let в своих примерах — Михей

@Бакуриу LYAH делает теперь упомяните let . Но продолжение. В LYAH Я читаю addThree :: Int -> Int -> Int -> Int (новая линия) addThree x y z = x + y + z но только второй вбегает GHCi с let . Почему? — изоморфизмы

@Bakuriu Да, но автор советует вам записывать свои определения во внешний файл и загружать его в GHCI, а не записывать их непосредственно в GHCI. И первое работает отлично. — суперзамп

Тогда это руководство совершенно неверно: Seas.upenn.edu/

cis194/lectures/01-intro.html . Тем не менее, это первое руководство, рекомендованное на сайте haskell! — Cammil

Когда вы вводите исходный файл Haskell,

Когда вы вводите непосредственно в ghci, вам нужно вводить let в начале строки:

ответ дан 31 мая ’11, 09:05

Почему не работает в GHCi? Почему есть разница в синтаксисе? — Бить

@Beat GHCi пытается оценивать выражения по умолчанию, а не синтаксический анализ операторов, тогда как формат файла противоположный. Вот почему, чтобы делать утверждения (например, устанавливать переменные, определять функции и т. Д.), Вы должны объявить, что вы используете let . Думайте о GHCi как о большом let . in . утверждение. — АЖФ

Хорошее практическое правило использования ghci заключается в том, что любой вводимый вами код должен соответствовать семантике do-block; то есть вы могли предположить синтаксически что вы программируете в монаде ввода-вывода (если это новая терминология, не волнуйтесь! Я настоятельно рекомендую прочитать это учебник).

Эта медитация Ответ иллюстрирует этот момент на примере и может дать более подробное представление о природе ввода-вывода и ghci.

ответ дан 23 мая ’17, 13:05

Этот ответ бесполезен для новичка. Он ищет простой действенный совет, чтобы двигаться вперед, а не сложные темы. Вы не объясняете полиномиальные произведения ребенку, изучающему таблицу умножения — она ​​не показывает, сколько вы знаете, это показывает, что вы не знаете, как поделиться тем, что вы знаете. — БТК

@btk: в какой-то момент каждый должен перестать быть новичком. Я начал изучать Haskell вчера и уверен, что через короткое время я пойму все, что говорит Раиз. — Вьетни Фуван

Это мой первый день изучения Haskell, и я нашел этот ответ очень полезным для понимания того, почему я должен использовать let ; Я подумал: «Черт возьми, зачем мне использовать let «а потом я прочитал это и был просветлен. — Брайан Тингл

Начиная с GHC 8.0.1 это больше не будет генерировать ошибку.

Источник

You stated you were given some functions to work with, but then didn’t use them! Perhaps I misunderstood. Your code seems jumbled and doesn’t seem to achieve what you would like it to. You have a call to getContents, which has type IO String but that function is supposed to be in the parser monad, not the io monad.

If you actually would like to use them, here is how:

readAsTuple :: Parser ComplexInt
readAsTuple = do
  _ <- char '('          
  x <- many digit
  _ <- char ','
  y <- many digit
  _ <- char ')'
  return $ ComplexInt (read x) (read y)

readAsNum :: Parser ComplexInt
readAsNum = do
  x <- many digit
  return $ ComplexInt (read x) 0

instance Read ComplexInt where
  readsPrec _ = runParser (readAsTuple +++ readAsNum)

This is fairly basic, as strings like " 42" (ones with spaces) will fail.

Usage:

> read "12" :: ComplexInt 
ComplexInt 12 0
> read "(12,1)" :: ComplexInt
ComplexInt 12 1

The Read type-class has a method called readsPrec; defining this method is sufficient to fully define the read instance for the type, and gives you the function read automatically.

What is readsPrec?

readsPrec :: Int -> String -> [(a, String)].
The first parameter is the precedence context; you can think of this as the precedence of the last thing that was parsed. This can range from 0 to 11. The default is 0. For simple parses like this you don’t even use it. For more complex (ie recursive) datatypes, changing the precedence context may change the parse.

The second parameter is the input string.

The output type is the possible parses and string remaining a parse terminates. For example:

>runStateT (char 'h') "hello world"
[('h',"ello world")]

Note that parsing is not-deterministic; every matching parse is returned.

>runStateT (many1 (char 'a')) "aa"
[("a","a"),("aa","")]

A parse is considered successful if the return list is a singleton list whose second value is the empty string; namely: [(x, "")] for some x. Empty lists, or lists where any of the remaining strings are not the empty string, give the error no parse and lists with more than one value give the error ambiguous parse.

26 Jul 2018

Reading time ~13 minutes

Oh, The Kinds of Errors You’ll See

Haskell has what I would consider to be 3 different types of errors: parse errors, definition errors, & type errors.

Parse errors occur when we have broken a formatting rule or some convention enforced by the compiler.

Once we fix all of those we will get definition errors. Definition errors occur when we are calling that function that isn’t defined by us in our scope or the function hasn’t been imported from another module.

Once we fix all our definition errors we’ll get type errors. Type errors occur when we told the compiler we would do something via our types & we haven’t followed through in our function. After you fix all those errors you’ll get your program to run!

We’re going to step through fixing a file that has various parse errors & then, at the end, have a file that compiles correctly. If you would like to follow along in your own REPL you can find the code here.

Here we have a file that’s breaking some formatting rules. Let’s try compiling this & see what error messages we get.

{-# LANGUAGE InstanceSigs #-}

import Control.Applicative

module Main where

mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth
        where truth = "sorry, that isn't true"

let lie = 
"this code will compile fine"

Error #1

[1 of 1] Compiling Main             ( format.hs, interpreted )

format.hs:5:1: error: parse error on input ‘module’
  |
5 | module Main where
  | ^^^^^^
Failed, no modules loaded.

Our first error upon loading the module is a parse error on input module. This error occurred on line 5 of our file. Let’s go look at it.

{-# LANGUAGE InstanceSigs #-}

import Control.Applicative

module Main where
-- ^ `module Main where` is line 5 of our file
mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth
        where truth = "sorry, that isn't true"

let lie = 
"this code will compile fine"

Top Of File

The rules, for what the top of Haskell files should look, are:

  • Language pragmas are listed at the top of the file
  • Module name is declared above imports & code
  • Imported modules listed before functions

I personally like to have LANGUAGE in all uppercase because I like to yell as much as possible in my code. If you decide to give your file a module name, it must be above the imported modules & functions, with a capitalized name. Then you list modules you would like to import into your file. Imported modules must come before your functions.

Fix #1 Order Matters

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth
      where truth = "sorry, that isn't true"

let lie = 
"this code will compile fine"

Here we’ve moved module Main where above our imported module. Let’s reload to see our next error.

Error #2

[1 of 1] Compiling Main             ( format.hs, interpreted )

format.hs:14:13: error: parse error on input ‘->’
   |
14 |       False -> "no broken rules here... " ++ truth
   |             ^^
Failed, no modules loaded.

The compiler tells us that we have a parse error on input right arrow. It shows us that the error in on line 14. Let’s go check out the code.

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth
      where truth = "sorry, that isn't true"

let lie = 
"this code will compile fine"

The error is on the line that starts with False, line 14. But there are a couple of other problems in the ruleBreaker & lie function too. So keep in mind the where block & the let for the rules we discuss next.

Indentation Rules

For this section, I’m assuming you’re using spaces & using whitespace to denote separation of code blocks. There are warnings by default in Haskell if you use tabs. You can also use curly braces in your code to denote separate blocks. Spaces & whitespace are my preference in Haskell because I think it makes my code look nice. :)

  • Code implementations start at least 1 space after the function name on the following line
rulebraker b = 
    case b of
        ...

My most common error is not having enough spaces between my function name & my implementation on the next line. You need to have the implementation 1 space over on the next line compared to the function name. This rule applies for let in expressions, case of expressions, guards, & where blocks!

  • New code blocks inside of other functions must be 1 space over to denote a new block
    case b of
      True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth

When you start a new block you need to indent those expressions by at least 1 space. Most people will use at least 2 spaces for readability. So here we can see that we need a new code block because of the use of a case of expression. If you’re using a control structure & the following code will be on a new line that’s a pretty good indication you will need to indent your next section.

  • Code blocks must spatially align
rulebraker b = 
    case b of
      True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth
        where truth = "sorry, that isn't true"

Our True & False here are in the same block because they’re both values our case b of can reduce to. Because these expressions are in the same block we need to make sure that they line up.

Fix #2

Here is our fixed indentation!

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = "sorry, that isn't true"

let lie = 
     "this code will compile fine"

Below is our code that wasn’t following our indentation rules.

rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
      False -> "no broken rules here... " ++ truth
      where truth = "sorry, that isn't true"

let lie = 
"this code will compile fine"

Indentation Fixed

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = "sorry, that isn't true"

let lie = 
     "this code will compile fine"

We fixed all our indentation problems by following the rules we just talked about! Let’s reload the file & see where we’re at with this file now.

Error #3

[1 of 1] Compiling Main             ( format.hs, interpreted )

format.hs:19:1: error:
    parse error (possibly incorrect indentation or mismatched brackets)
Failed, no modules loaded.

Parse error. Possibly incorrect indentation. I know what you’re thinking.

You said we fixed all our indentation!

I promise I didn’t lie.

This error occurs on line 19 & we don’t have a line 19 in our file! Let’s go look at the end of the file instead.

let lie = 
     "this code will compile fine"

Why doesn’t this work? Well, let’s look at the rule.

Functions are Top Level Declarations

let & where are meant to define functions inside other functions to a local scope.

Just a function name at the top level will be fine!

We can’t have anything but functions at the top level of our file. You might be use to declaring things that look like variables using an identifier to distinguish it from functions, but in Haskell everything is a function!

Fix #3

Here is the fixed version of our lie function.

lie = 
  "this code will compile fine"

Here is the old version that didn’t compile.

let lie = 
     "this code will compile fine"

Functions at The Top Level

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = 
             "sorry, that isn't true"

lie = 
 "this code will compile fine"

We got rid of our let here & now let’s recompile.

Error #4

[1 of 1] Compiling Main             ( format.hs, interpreted )

format.hs:10:1: error:
    The type signature for ‘ruleBreaker’ lacks an 
    accompanying binding
   |
10 | ruleBreaker :: Bool -> String
   | ^^^^^^^^^^^
Failed, no modules loaded.

We’ve moved onto definition errors now! We won’t see any more parse errors now! When you get to this stage in your own files you can congratulate yourself on making through 1 stage of the compilation process. :)

The type signature for ruleBreaker doesn’t have a function associated with it. Let’s go look at line 10 of our file.

ruleBreaker :: Bool -> String
rulebraker b = 
  case b of
    ...

The type signature & the function name are different. You may notice that there is a typo in one of them.

If you have a type signature, you must have a function implementation with it. We’ll just fix our typo.

Type signatures for functions that exist

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

mymain :: Int
mymain = print "hello world"

ruleBreaker :: Bool -> String
ruleBreaker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = 
             "sorry, that isn't true"

lie = 
 "this code will compile fine"

We fixed our typo & now let’s reload our code!

Error #5

[1 of 1] Compiling Main             ( format.hs, interpreted )

format.hs:1:1: error:
    The IO action ‘main’ is not defined in module ‘Main’
  |
1 | module Main where
  | ^
Failed, no modules loaded.

The next error we get here says that the function main isn’t found in our module Main. Let’s look at the code & see if that’s true.

{-# LANGUAGE InstanceSigs #-}
-- | We have a module called Main
module Main where

import Control.Applicative
-- | We have a function called `mymain`
mymain :: Int
mymain = print "hello world"

We can see in the code that we have a module Main on line 3 & we don’t have a function called main anywhere in our file. Instead we have a function called mymain.

module Main where

The rule we’re breaking here is that if you use module Main you have to have a function called main. If for whatever reason you don’t want to have a main function, just name your module anything else (that starts with a capital letter).

Fix #5 main for Main

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

main :: Int
main = print "hello world"

ruleBreaker :: Bool -> String
ruleBreaker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = 
             "sorry, that isn't true"

lie = 
 "this code will compile fine"

So we will rename mymain to main & reload our code to see how we’re doing.

Error #6

[1 of 1] Compiling Main             ( format.hs, interpreted )

format.hs:8:1: error:
    • Couldn't match expected type ‘IO t0’ with actual type ‘Int’
    • In the expression: main
      When checking the type of the IO action ‘main’
   |
 8 | main = print "hello world"
   | ^

format.hs:8:8: error:
    • Couldn't match expected type ‘Int’ with actual type ‘IO ()’
    • In the expression: print "hello world"
      In an equation for ‘main’: main = print "hello world"
   |
 8 | main = print "hello world"
   |        ^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

We fixed the definition errors we got & now we’ve gotten some type errors!

Really this is 2 errors, but they go really well hand in hand. The first error says we couldn’t match the expected type of main, which is IO of something, with the actual type, in the type signature, Int. The compiler tells us on the 2nd error that we told them we would give them an Int, but we are actually providing an IO (). It points to line 8, specifically at the expression: print "hello world". This is expected because print has the type is a to IO () where a has the constraint to have an instance of Show. Let’s go look at those lines.

main :: Int
main = print "hello world"

We did in fact say we would return an Int here & we aren’t doing it.

main :: IO Type

main always returns IO of some type. Usually main gives us back a value of IO ()

In our main function we use print. print has the type a to IO (). So we know we’ll want to return IO ().

The rule for using the function main is that main must return IO of some type. It doesn’t have to be IO (), but print has the return type of IO (). Let’s change our type signature of main to IO ().

Fix #6 IO & main, together forever

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

main :: IO ()
main = print "hello world"

ruleBreaker :: Bool -> String
ruleBreaker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = 
             "sorry, that isn't true"

lie = 
 "this code will compile fine"

Here we are, main has the type IO (), which reflects the type that print "hello world" gives us. Let’s reload.

[1 of 1] Compiling Main             ( format.hs, interpreted )
Ok, one module loaded.

Sweet! Our file is properly formatted now! There are no more errors in our code & this will run fine. So… just one more thing. :)

Properly formatted file!

{-# LANGUAGE InstanceSigs #-}

module Main where

import Control.Applicative

main :: IO ()
main = print "hello world"

ruleBreaker :: Bool -> String
ruleBreaker b = 
  case b of
    True -> "yeah this code doesn't follow the rules"
    False -> "no broken rules here... " ++ truth
      where truth = 
             "it's true!"

lie = 
 "this code won't compile fine"

Let’s change the strings to reflect that our code compiles haha.

If you notice any issues with this post please submit an issue here. If this was easy for you to follow along with please consider adding to the Haskell wiki on compiler errors.

As a neophyte to functional programming and Haskell, with full appreciation over the succinctly outputted type errors, for a long time I felt something was remiss with the output of syntax errors. In this post I present a preliminary fix to GHC that improves in the aforementioned arena.

Like many other compilers who have not yet forsaken the annotated BNF approach of describing a syntax and parser, Haskell’s prominent compiler GHC uses Happy in order to generate efficient parsing tables for the syntax.

The problem

While there are some hand-coded hints about errors being detected while compiling a module with GHC, other errors sometimes don’t provide any extra information.

example 1 — source
test i = case i of 2
main = return ()
example 1 — output
example1.hs:2:1:
    parse error (possibly incorrect indentation or mismatched brackets)

And another example:

example 2 — source
test i = i
  where e

main = return ()
example 2 — output
example2.hs:4:1:
    parse error (possibly incorrect indentation or mismatched brackets)

As you can see, we have the same error on both occasions. Is it possible to generate an error message that differentiates between the two, automatically? Apparently yes.

Making it happier

Thanks to the parsing tables, the parser does know which tokens can follow at the place of the error. So, I took the time to modify Happy and modify GHC to produce the following results. The gist of these changes is to allow passing the list of next possible tokens to the user-provided error function. The results are not perfect, but they are interesting nonetheless.

Let’s repeat the previous examples and add some more.

example 1 — source
test i = case i of 2
main = return ()
example 1 — output
example1.hs:2:1:
    parse error (possibly incorrect indentation or mismatched brackets), possible tokens: '|' '->'

And for the second example:

example 2 — source
test i = i
  where e

main = return ()
example 2 — output
example2.hs:4:1:
    parse error (possibly incorrect indentation or mismatched brackets), possible tokens: '=' '|'

A third example:

example 3 — source
data X = X {
    bla :: Int
    test :: Int
  }
example 3 — output
example3.hs:3:10:
    parse error on input, possible tokens: '}' ‘::’

The avid reader would wonder at this point, why ‘::’ is mentioned and ‘,’ is not mentioned in the possible tokens list. We observe that the error is after ‘Int test’, probably much deeper and in a different syntax production than the one that defines each part of a record. With more time I would examine the Action and Goto tables generated by Happy from the extensive definition of the syntax in GHC.

example 4 — source
data X = X {
    bla :: Int
  , test :: Int
  } deriving

main = return ()
example 4 — output
example4.hs:6:1:
    parse error (possibly incorrect indentation or mismatched brackets), possible tokens: '(' CONID QCONID PREFIXQCONSYM

Here it gets more interesting, because the parser now outputs token identifiers that are not just punctuation or operators, but user-defined identifier strings. These are the same names used when defining the syntax.

example 5 — source
main = = return ()
example 5 — output
example5.hs:1:8:
    parse error on input, possible tokens: '_' 'as' 'case' 'do' 'hiding' 'if' 'let' 'qualified' 'forall' 'export' 'label' 'dynamic' 'safe' 'interruptible' 'unsafe' 'mdo' 'family' 'role' 'stdcall' 'ccall' 'capi' 'prim' 'javascript' 'proc' 'group' 'static' '{-# CORE' '{-# SCC' '{-# GENERATED' '\' '~' '-' '[' '[:' '(' '(#' '(|' SIMPLEQUOTE VARID CONID QVARID QCONID PREFIXQVARSYM PREFIXQCONSYM IPDUPVARID CHAR STRING INTEGER RATIONAL PRIMCHAR PRIMSTRING PRIMINTEGER PRIMWORD PRIMFLOAT PRIMDOUBLE '[|' '[p|' '[t|' '[d|' '[||' TH_ID_SPLICE '$(' TH_ID_TY_SPLICE '$$(' TH_TY_QUOTE TH_QUASIQUOTE TH_QQUASIQUOTE ‘=’

Obviously, there are many things that could come instead of the second =. Perhaps it would require some community debate regarding how to present this behemoth list of possible tokens to the user in this case.

Contents

  • 1 Common Mistakes and Incorrect Beliefs By Haskell Beginners
    • 1.1 Indentation
    • 1.2 If / Then / Else
    • 1.3 Binding of Type Signatures
    • 1.4 do Notation
    • 1.5 Iterating Over a List
    • 1.6 Guards
    • 1.7 Parentheses
  • 2 See also

Common Mistakes and Incorrect Beliefs By Haskell Beginners

People going from zero to Haskell are likely to gain a misunderstanding or miss a point that isn’t stressed enough. Here are some mistakes that have been observed from multiple sources.

Indentation

Perhaps the first trip-up — you might understand that indentation defines where a code block starts and the lack of an equal amount of indentation indicates the previous code block ended. What some miss is that then and else, if used within a section of code where indentation matters, must be indented deeper than the if statement. That is, the position of the «else» in the following is a syntax error:

do  if boolean then
        expr1
    else
        expr2

The following is correct:

do  if boolean
        then expr1
        else expr2

Or they can be on the same line as the if:

if boolean then expr1 else expr2

Fortunately this misfeature is fixed in Haskell 2010, and the first snippet is valid in compilers that support it (e.g. GHC 7.0.1 and later).

If / Then / Else

if-then statements must always include an ‘else’ portion. It might be best not to think of if-then-else as flow control, as in most imperative languages, but think of it as construction of a value using a well formed expression.


x = b ? y : z;

The above is valid C code, a ternary operation, that’s used quite commonly as a shortcut to typing out a full if-then-else block. It states that if b is true then x = y otherwise x = z. Notice how this makes no sense without z. Similarly, in Haskell an if/then makes no sense without an else.

let x = if b then y   -- compare to x = b ? y

What is x when b is false? One should also recognize that the types returned by the then and else branches must match due to Haskell’s strong and static type system.

When if is used for sequencing IO it is not uncommon to see an else that returns a null value:

main = do
    startNetwork <- askUser "Network? "
    if startNetwork
        then do iface <- initNetworkInterface
                handlePackets iface
        else return ()

Such uses can be more succinct if they use the when function (from the Control.Monad module):

main = do
    startNetwork <- askUser "Network? "
    when startNetwork $ do
        iface <- initNetworkInterface
        handlePackets iface

Binding of Type Signatures

Due to the typeclass overloading of numbers, lists of numbers are often typed as:

ghci> [1,2,3,4] :: [Float]

This works fine when the list stands alone, but when applying a function take note the function application binds stronger than the type signature. This means the below signature is invalid:

ghci> map floor [1,2,3,4] :: [Float]

and should instead be:

ghci> map floor ([1,2,3,4] :: [Float])

or alternatively put the type signature on one of the elements:

ghci> map floor [1,2,3,4::Float]

do Notation

If the do notation page ever exists I’ll advise you to check it out. Until then, understand that a missing do from the top of a function or code block can result in your compiler giving an error message citing a much later line number. Also, any new blocks (ex: from an if or case) must have their own do, even if the higher level code block already had one.

Sorry this isn’t the full picture — for an inverse point of view see do notation considered harmful.

Iterating Over a List

Some beginners confuse a single-element list pattern (such as [x]) with a pattern that iterates over every element in the list.

One example that recently (in April, 2008) appeared on the Haskell-Cafe mailing list (see the reply post Re: Embedding newlines into a string?) was the following. Here, one coder attempted to write a function hanoi to solve the Towers of Hanoi problem, but to code it so that each tower could be named polymorphically, using, for example, either Chars or Ints. The problematic code segment was the following:

hanoi_shower :: Show a => [(a, a)] -> String
hanoi_shower [(a, b)] = "Move " ++ show a ++ " to " ++ show b ++ "."

in the following program:

hanoi :: a -> a -> a -> Int -> [(a, a)]
hanoi source using dest n
    | n == 1 = [(source, dest)]
    | otherwise = hanoi source dest using (n-1)
                  ++ hanoi source using dest 1
                         ++ hanoi using source dest (n-1)

hanoi_shower :: Show a => [(a, a)] -> String
hanoi_shower [(a, b)] = "Move " ++ show a ++ " to " ++ show b ++ "."

The coder tried to run the code in WinHugs as follows:

Main> putStr (hanoi_shower (hanoi 'a' 'b' 'c' 2))

However, this was the result:

Program error: pattern match failure: hanoi_shower
[('a','b'),('a','c')] ++ ([] ++ hanoi 'b' 'a' 'c' (2 - 1))

The problem was that the parameter [(a, b)] to hanoi_shower only matched the first element of the list, but didn’t iterate over the list as intended.

Here is a corrected version of the code above:

hanoi_shower :: Show a => [(a, a)] -> String
hanoi_shower moves = unlines ["Move " ++ show a ++ " to "++ show b ++ "." | (a, b) <- moves]

Here, moves is pattern-matched to type [(a, a)] (a list of pairs). The problem is how to iterate over the elements (pairs) of the list while separating the first a of each pair from the second a.

The solution above uses list comprehension: The generator (a, b) <- moves feeds each pair in turn to the left-hand expression (a, b), and this pair is mapped to the left expression, "Move " ++ show a ++ " to "++ show b ++ ".", building a new list of sentences representing moves. Then, the function unlines breaks this list into a sequence of lines.

Here is the result of executing the above code in WinHugs:

Main> putStr (hanoi_shower (hanoi 'a' 'b' 'c' 2))
Move 'a' to 'b'.
Move 'a' to 'c'.
Move 'b' to 'c'.

Main> putStr (hanoi_shower (hanoi 1 2 3 2))
Move 1 to 2.
Move 1 to 3.
Move 2 to 3.

Notice that since a and b in (a, b) are polymorphic types, they can range over both Chars and Ints.

Another way of writing hanoi_shower, using map, is as follows:

hanoi_shower :: Show a => [(a, a)] -> String
hanoi_shower moves = unlines (map move moves)
                     where move (a, b) = "Move " ++ show a ++ " to "++ show b ++ "."

Here, move is mapped over moves, and each pair (a, b) of moves is pattern-matched against "Move " ++ show a ++ " to "++ show b ++ "."

Another way to map over a list is to use recursion, although this method is considered non-idiomatic Haskell (Haskellers generally prefer using higher-order functions over recursion when possible):

hanoi :: a -> a -> a -> Int -> [(a, a)]
hanoi source using dest n
    | n == 0 = []
    | n == 1 = [(source, dest)]
    | otherwise = hanoi source dest using (n-1) 
                  ++ hanoi source using dest 1
                         ++ hanoi using source dest (n-1)

hanoi_shower :: Show a => [(a, a)] -> String
hanoi_shower [] = ""
hanoi_shower ((a, b):moves) = unlines ["Move " ++ show a ++ " to "++ show b ++ "."] ++ hanoi_shower moves

Here, in hanoi_shower, the base case is simply an empty list []. At each recursive step, a list of type [(a, a)] (a list of pairs) is mapped against the parameter (a, b):moves of hanoi_shower. This separates the head of the list (a, b) from the tail of the list moves, which then is further matched against ((a, b):moves) on the next recursive call.

There are other ways of iterating over lists as well. One advantage of Haskell is that there are often many ways of performing the same action, including iterating over lists.

Guards

(The following two tips on guards were contributed by the user 7stud in the thread «Top beginner mistakes» (see https://web.archive.org/web/20180127010825/http://article.gmane.org:80/gmane.comp.lang.haskell.beginners/1121) on the Haskell-Beginners mailing list on Wed, 4 Mar 2009 21:54:05 +0000 (UTC).)

Some beginners make the mistake of putting an equals sign after a function name when using guards; viz.:

myfunction x y =
    | x < 2              = "a"
    | y > 20             = "b"
    | otherwise          = "c"

This causes a cryptic error message similar to the following to be displayed:

dhask.hs:2:4: parse error on input `|' Failed, modules loaded: none.

Another common mistake that some beginners make is writing «if» in front of the guard conditions; viz.:

myfunction x y
    | if x < 2           = "a"
    | if y > 20          = "b"
    | otherwise          = "c"

This causes a mysterious error message similar to the following to be shown:

dhask.hs:2:25: parse error on input `=' Failed, modules loaded: none.

In both cases, the error messages don’t help to identify the problem.

(Entry added by Benjamin L. Russell.)

Parentheses

(The following tip on parentheses was contributed by the user 7stud in the thread «Top beginner mistakes» (see https://web.archive.org/web/20180127010825/http://article.gmane.org:80/gmane.comp.lang.haskell.beginners/1121) on the Haskell-Beginners mailing list on Wed, 4 Mar 2009 21:54:05 +0000 (UTC).)

Some beginners make the mistake of not putting parentheses around arguments of the form x:xs; viz.:

dosomething x:xs = head xs

This causes an ambiguous error message similar to the following to be shown:

dhask.hs:1:0: Parse error in pattern Failed, modules loaded: none.

Here, the error message doesn’t help to recognize the problem.

(Entry added by Benjamin L. Russell.)

See also

  • What a Monad is not

Я новичок в Haskell, и после запуска ghci Я пытался:

f x = 2 * x

и я получил:

<interactive>:1:4: parse error on input `='

чего я не понимаю.

Как ни странно, раньше это работало хорошо. Я полагаю, что я неправильно сконфигурировал Haskell. Переустановка ghc6 не решает проблемы.

Для информации я использую Ubuntu 10.4, а версия ghc6 — 6.12.1-12.

4 ответы

В GHCi 7.x или ниже вам понадобится let определять вещи в нем.

Prelude> let f x = x * 2
Prelude> f 4
8

Начиная с GHC 8.0.1, привязки верхнего уровня поддерживаются в GHCi, поэтому код OP будет работать без изменений.

GHCi, version 8.0.1.20161213: http://www.haskell.org/ghc/  :? for help
Prelude> f x = x * 2
Prelude> f 4
8

Создан 11 янв.

Когда вы вводите исходный файл Haskell,

f x = 2 * x

правильно.

Когда вы вводите непосредственно в ghci, вам нужно вводить let в начале строки:

let f x = 2 * x

ответ дан 31 мая ’11, 09:05

Хорошее практическое правило использования ghci заключается в том, что любой вводимый вами код должен соответствовать семантике do-block; то есть вы могли предположить синтаксически что вы программируете в монаде ввода-вывода (если это новая терминология, не волнуйтесь! Я настоятельно рекомендую прочитать это учебник).

Эта медитация Ответ иллюстрирует этот момент на примере и может дать более подробное представление о природе ввода-вывода и ghci.

ответ дан 23 мая ’17, 13:05

Начиная с GHC 8.0.1 это больше не будет генерировать ошибку.

ответ дан 15 окт ’16, 05:10

Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками

haskell

or задайте свой вопрос.

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Parse error no category context for line
  • Parse error invalid numeric literal at line
  • Parse error invalid body indentation level
  • Parse error in template argument list ардуино
  • Parse error fstab

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии