简体   繁体   中英

explanation of haskell function

The code I am looking at contains this top level function:

starman :: String -> Int -> IO ()
starman word n = turn word ['-' | x <- word] n

I can see that this is a function that takes 2 arguments and then calls the turn function that looks like this:

turn :: String -> String -> Int -> IO ()
turn word display n =
  do if n==0
       then putStrLn "You lose"
       else if word==display
              then putStrLn "You win!"
              else mkguess word display n

What I don't understand is what this means:

word ['-' | x <- word]

The full line is:

starman word n = turn word ['-' | x <- word] n

turn is called with three parameters:

word
['-' | x <- word]
n

The middle one is the one you're having trouble with. It can be read as: "a hyphen for each character in word."

So ['-' | x <- "hello"] ['-' | x <- "hello"] is "-----" .

This construct is known as list comprehension .

EDIT

The list comprehension does the same thing as this, which is perhaps clearer in intent?

replicate (length word) '-'

word is the first argument to the turn function.

['-' | x <- word] ['-' | x <- word] is the second argument and it's a list containing one '-' for each letter x in word . The fact that we give each letter the name x accomplishes nothing though, as we never refer to it, so we might as well write ['-' | _ <- word] ['-' | _ <- word] .

This syntax is known as a list comprehension and is meant to look similar to set notation.

Actually, in the following expression

turn word ['-' | x <- word] n

there a function ( turn ) call, with three arguments: word , ['-' | x <- word] ['-' | x <- word] , and n . So ['-' | x <- word] ['-' | x <- word] is independent of word .

Now, what is the meaning of ['-' | x <- word] ['-' | x <- word] ? This is a list comprehension, so it's an expression that constructs a list. In order to understand this, you have to remember that strings in haskell are just lists of characters. So word is a list. The x <- word means: take each element of the list word , call it that element x and then for each such element, evaluate the expression '-' and collect all those values into a list. In this case, the expression '-' does not reference x , so it will always evaluate to '-' . So in other words, we are taking the list of characters word and creating a list where each element-character is replaces by '-' .

Here are some equivalent ways to do the same thing:

['-' | _ <- word]              -- use the anonymous variable, we don't need the element
map (\_ -> '-') word
map (const '-') word
'-' <$ word                    -- my favorite one!
replicate (length word) '-'    -- the least preferrable way

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM