如何打印 Maybe?

How can I print a Maybe?

import Data.List
import Data.Char
import Data.Maybe



phoneBook = 
    [("betty", "555-2928")
    ,("bonny", "092-1029")
    ,("pasty", "493-9202")
    ]

findKey :: (Eq k) => k ->  [(k,v)] -> Maybe v
findKey key [] = Nothing
findKey key ((k,v):xs) 
     | key == k = Just v
     | otherwise = findKey key xs

main :: IO()
main = do
    putStrLn "hello"

    putStrLn (show fromMaybe (findKey "penny" phoneBook))
    putStrLn (show fromMaybe (findKey "bonny" phoneBook))

============================================= =================

dictionary.hs:24:22:
    Couldn't match type `Maybe [Char]' with `[Char]'
    Expected type: String
      Actual type: Maybe [Char]
    In the return type of a call of `findKey'
    In the first argument of `putStrLn', namely
      `((findKey "bonny" phoneBook))'
    In a stmt of a 'do' block: putStrLn ((findKey "bonny" phoneBook))

为什么我的 putStrLn 在尝试打印来自 fromMaybe 的值时抛出错误?

show fromMaybe (findKey "penny" phoneBook)

将两个参数传递给 show:第一个是 fromMaybe,第二个是 findKey "penny" phoneBook。您需要加括号才能只传递一个:

show (fromMaybe (findKey "penny" phoneBook))

但是还有一个问题。 fromMaybe 有两个参数,而你只给了它一个。如果 maybe 结果是 Nothing.

,它的第一个参数应该是 return 的默认值

您首先必须了解 fromMaybe 的工作原理。引用文档,

The fromMaybe function takes a default value and and Maybe value. If the Maybe is Nothing, it returns the default values; otherwise, it returns the value contained in the Maybe.

因此,您需要将两个值传递给 fromMaybe,第一个是要使用的默认值,以防 Maybe 变成 Nothing。但是在你的情况下,你只传递了一个参数,

fromMaybe (findKey "penny" phoneBook)
fromMaybe (findKey "bonny" phoneBook)

您只是将实际的 Maybe 值传递给 used,缺少默认值。所以,将其更改为

fromMaybe "Not Found" (findKey "penny" phoneBook)
fromMaybe "Not Found" (findKey "bonny" phoneBook)

现在我们对 fromMaybe 部分没问题了。但是,它仍然会失败,如果你的代码是这样的

show fromMaybe "Not Found" (findKey "penny" phoneBook)
show fromMaybe "Not Found" (findKey "bonny" phoneBook)

因为,这意味着您将三个参数传递给 show,即 fromMaybe"Not Found"(findKey "penny" phoneBook)。但是 show 只需要一个值。引用 show documentation,

show :: a -> String

A specialised variant of showsPrec, using precedence context zero, and returning an ordinary String.

它只需要值和 returns 一个 String。所以你只需要传递 fromMaybe 返回的值,就像这样

show (fromMaybe "Not Found" (findKey "penny" phoneBook))
show (fromMaybe "Not Found" (findKey "bonny" phoneBook))

它仍然会失败,因为 putStrLn 只需要一个参数,根据 the documentation,

putStrLn :: String -> IO ()

The same as putStr, but adds a newline character.

所以,你只需要将show的结果传递给putStrLn,就像这样

putStrLn (show (fromMaybe "Not Found" (findKey "penny" phoneBook)))
putStrLn (show (fromMaybe "Not Found" (findKey "bonny" phoneBook)))

现在,它将打印,

hello
"Not Found"
"092-1029"

注1:如果不喜欢那么多括号,可以使用$运算符,它做的是隐函数应用。引用 $,

的文档

($) :: (a -> b) -> a -> b

Application operator. This operator is redundant, since ordinary application (f x) means the same as (f $ x). However, $ has low, right-associative binding precedence, so it sometimes allows parentheses to be omitted; for example:

   f $ g $ h x  =  f (g (h x))

It is also useful in higher-order situations, such as map ($ 0) xs, or zipWith ($) fs xs.

因此,您可以简单地删除不必要的括号并像这样编写代码

putStrLn $ show $ fromMaybe "Not Found" (findKey "penny" phoneBook)
putStrLn $ show $ fromMaybe "Not Found" (findKey "bonny" phoneBook)

注意 2: 在这种特殊情况下,由于您的 fromMaybe 已经 returns 一个 [Char],您可以简单地跳过 show 并将 fromMaybe 的结果传递给 putStrLn,像这样

putStrLn $ fromMaybe "Not Found" (findKey "penny" phoneBook)
putStrLn $ fromMaybe "Not Found" (findKey "bonny" phoneBook)