Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell nested where clauses

I am a beginner coder in haskell, while doing an exercise from the first chapter of this amazing book: http://book.realworldhaskell.org/read/getting-started.html I came across this issue:

-- test comment
main = interact wordCount
 where
     wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs  ++ "\n")
     where
         ls = lines input
         ws = length words input
         cs = length input



wonderbox:ch01 manasapte$ runghc WC < quux.txt
WC.hs:5:9: parse error on input ‘where’

Why can I not nest my wheres ?

like image 258
user1639848 Avatar asked Mar 16 '15 02:03

user1639848


2 Answers

Since your second where is attached to the wordCount definition, it needs to be indented more than it. (Although you will still have some other errors afterward.)

like image 97
Ørjan Johansen Avatar answered Sep 19 '22 16:09

Ørjan Johansen


Others have already answered. I will just add some more explanation.

Simplifying a bit, the Haskell indentation rule is:

  • Some keywords start a block of things (where,let,do,case ... of).
  • Find the first word after such keywords and note its indentation. Name the column it occurs the pivot column.
  • Start a line exactly on the pivot to define a new entry in the block.
  • Start a line after the pivot to continue the entry started in the previous lines.
  • Start a line before the pivot to end the block.

Hence,

where
     wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs  ++ "\n")
     where
         ls = lines input
         ws = length words input
         cs = length input

Actually means

where {
     wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs  ++ "\n")
     ;
     where {     -- same column, new entry
         ls = lines input
         ;   -- same column, new entry
         ws = length words input
         ;   -- same column, new entry
         cs = length input
         }
     }

which treats the second where as a separate definition unrelated to wordCount. If we indent it more, it will work:

where {
     wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs  ++ "\n")
       where {     -- after the pivot, same entry
         ls = lines input
         ;
         ws = length words input
         ;
         cs = length input
         }
     }
like image 31
chi Avatar answered Sep 18 '22 16:09

chi