我有一个代码片段,如下所示
displayAge :: Show a => Maybe a -> IO ()
displayAge maybeAge =
case maybeAge of
Nothing -> putStrLn "Invalid year"
Just maybeAge -> putStrLn $ show maybeAge
此函数从控制台获取其参数,并通过readMay
函数传递给它,如下所示;
main = do
putStrLn "Your birth year"
strYear <- getLine
let maybeAge = do
intYear <- readMay strYear
return (processYear intYear)
displayAge maybeAge
请解释一下displayAge
函数的类型声明。为什么使用Show a
?
答案 0 :(得分:5)
displayAge
取Maybe
类a
的值,其中a
是任何类型Show
n。
首先阅读Haskell签名中=>
右侧的内容(即Maybe a -> IO ()
答案 1 :(得分:0)
所以,这是一个类型声明,所以它会告诉你需要提供给函数displayAge
的内容,以便类型检查器满意。后面的行实际上描述了函数的工作原理。类型声明(几乎总是)是可选的,但它们是重要的文档,并且经常使错误消息更有意义,因为编译器现在知道你想要做什么,并且可以将它与你实际做的相比较。
Show a
声明的第一部分,=>
之前的部分告诉了我们a
的一些内容。我们注意到a
是小写的,因此不是类型而是类型变量。实际使用displayAge
函数时,您可以使用任何类型代替a
(Int,String,[Double]等...)但这表示必须有{{} 1}}该类型的实例。所以几乎任何不是函数的类型。如果haskell中的类仍然让您感到困惑,请查看this section的Learn You a Haskell for Great Good(实际上它与_Why关于Ruby的教程一样好)
Show
有许多方法可以读取Haskell类型的签名,但如果是新的,它可以帮助在最后一个箭头(Maybe a
)之前考虑所有类型作为&#34;输入&#34;最后的类型为&#34;输出。&#34;这个想法错过了currying和一流的功能,但它确实可以帮助你开始。
因此,此功能需要->
,并会为您提供Maybe a
。
那么IO()
是什么?如果您不熟悉Maybe a
类型,您当然应该努力成为这样的类型。这是二阶类型。这意味着,为了使用它,你需要给它一些其他类型来包含。也许拥有其他类型。因此Maybe
成立并Maybe Int
,Int
成立Maybe String
。但是这个函数被设计为使用String
来保存任何类型(这么长时间它有一个像我们上面提到的Show实例)。再次注意小写Maybe
如果此函数特别需要某种类型,它将使用以大写字母开头的类型。
a
好的,这可能是困难的部分。这个功能而不是计算一些新的价值,对现实世界做了一些事情 - 所有存在于haskell世界之外的东西都是现实世界。因此,用户输入和输出,网络内容和可变内存都必须进入IO类型。 (是的,它是二阶就像Maybe)这是着名的,可爱的IO monad,我们希望你听说过,并会学会爱。当函数附带类型IO()
时,表示执行某事而不是返回值。在我们的例子中,我们认为它应该显示和年龄,对吗?您需要在IO()
块中使用displayAge
,例如do
函数*。
*不严格来说,你可以使用bind(main
)代替,但是这显然是一个初学者的问题,我们有关于不编写monad教程的规则,对吗?