所以我试着写一些Haskell,我遇到了这个让我想把头撞在墙上的问题.
printGrade points = case points of
points | 0 <= points && points < 50 -> 5.0
points | 50 <= points && points < 54 -> 4.0
points | 54 <= points && points < 58 -> 3.7
points | 58 <= points && points < 62 -> 3.3
points | 62 <= points && points < 66 -> 3.0
points | 66 <= points && points < 70 -> 2.7
points | 70 <= points && points < 74 -> 2.3
points | 74 <= points && points < 78 -> 2.0
points | 78 <= points && points < 82 -> 1.7
points | 82 <= points && points < 86 -> 1.3
points | 86 <= points && points < 100 -> 1.0
note a b c d =
if d > 100 || c > 20
then return "Wrong input"
else if a == False || b == False
then printGrade d
else printGrade (c + d)
Run Code Online (Sandbox Code Playgroud)
当我尝试运行代码时,它编译没有问题,但实际上调用该函数会带来此错误
<interactive>:91:1: error:
• Ambiguous type variable ‘m0’ arising from a use of ‘print’
prevents the constraint ‘(Show (m0 [Char]))’ from being solved.
Probable fix: use a type annotation to specify what ‘m0’ should be.
These potential instances exist:
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
instance (Show a, Show b) => Show (a, b) -- Defined in ‘GHC.Show’
instance (Show a, Show b, Show c) => Show (a, b, c)
-- Defined in ‘GHC.Show’
...plus 13 others
...plus two instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it
Run Code Online (Sandbox Code Playgroud)
我知道它与"返回错误的输入"有关,但我不知道解决这个问题的方法,因为我必须在某个时候打印出一个字符串.(我试过show/print/putStrLn导致另一个错误)
通常,以Haskell开头的人使用该return :: Monad m => a -> m a函数,因为在命令式世界中,几乎所有[命令式]编程语言都为return 关键字分配了几乎相同的语义.然而,在Haskell中,return是一个函数(不是关键字),它在monad的上下文中使用.虽然monad非常强大,但我建议首先看看这个结构在使用之前是如何工作的return.一个提示:它并不像在命令式世界中那样有效.
我们可以删除该return功能,例如:
note a b c d =
if d > 100 || c > 20
then "Wrong input"
else if a == False || b == False
then printGrade d
else printGrade (c + d)Run Code Online (Sandbox Code Playgroud)
但后来我们得到一个新的错误:
<interactive>:20:18: error:
• Could not deduce (Fractional [Char])
arising from a use of ‘printGrade’
from the context: (Num a, Ord a)
bound by the inferred type of
note :: (Num a, Ord a) => Bool -> Bool -> a -> a -> [Char]
at <interactive>:(16,1)-(21,35)
• In the expression: printGrade d
In the expression:
if a == False || b == False then
printGrade d
else
printGrade (c + d)
In the expression:
if d > 100 || c > 20 then
"Wrong input"
else
if a == False || b == False then
printGrade d
else
printGrade (c + d)
Run Code Online (Sandbox Code Playgroud)
现在Haskell遇到了返回类型的问题.确实printGrade返回了类似的值1.0,这是一种Fractional类型(后面可以指定的类型,但文字表明它应该是一种Fractional类型).并且它表示你也返回一个字符串("Wrong input"),并且因为a String不是一个Fractional类型,所以存在不匹配.我们可以通过调用解决这个问题show上的结果printGrade(我建议你重命名功能,因为该功能并没有打印任何东西),这样我们转换Fractional型成String,所以现在我们得到:
note a b c d =
if d > 100 || c > 20
then "Wrong input"
else if a == False || b == False
then show (printGrade d)
else show (printGrade (c + d))Run Code Online (Sandbox Code Playgroud)
现在该程序将编译,但它相当不优雅.例如,您case在printGrade函数中使用了a ,但实际上并没有执行任何模式匹配.我们可以使用警卫,例如:
grade :: (Num a, Ord a, Fractional b) => a -> b
grade points | points < 0 = error "too small"
| points < 50 = 5.0
| points < 54 = 4.0
| points < 58 = 3.7
| points < 62 = 3.3
| points < 66 = 3.0
| points < 70 = 2.7
| points < 74 = 2.3
| points < 78 = 2.0
| points < 82 = 1.7
| points < 86 = 1.3
| points < 100 = 1.0
| otherwise = error "too large"Run Code Online (Sandbox Code Playgroud)
因此,我们在每种情况下使用一个防护装置,而且不需要检查该值是否例如小于0,因为在那种情况下前一个防护装置将被解雇.
我们可以对note函数使用相同的技术:使用模式和保护来匹配值:
note :: (Ord a, Num a) => Bool -> Bool -> a -> a -> String
note _ _ c d | d > 100 || c > 20 = "Wrong input"
note False False _ d = show (printGrade d)
note _ _ c d = show (printGrade (c + d))Run Code Online (Sandbox Code Playgroud)