所以我想写一些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)
当我尝试运行代码时,它编译没有问题,但实际调用该函数会带来此错误
<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
我知道它与“返回错误的输入”有关,但我不知道解决这个问题的方法,因为我必须在某个时候打印出一个字符串。 (我尝试过show / print / putStrLn导致另一个错误)
答案 0 :(得分:5)
通常,以Haskell开头的人使用return :: Monad m => a -> m a
函数,因为在命令式世界中,几乎所有[命令式]编程语言都为return
关键字指定了几乎相同的语义< / em>的。但是在Haskell中,return
是函数(不是关键字),它在 monads 的上下文中使用。虽然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)
然后我们得到一个新错误:
<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)
现在Haskell遇到了返回类型的问题。确实printGrade
会返回1.0
之类的值,这是Fractional
类型(后面可以指定的类型,但文字表明它应该是Fractional
类型)。并且它表示您也返回一个字符串("Wrong input"
),并且由于String
不是Fractional
类型,因此存在不匹配。我们可以通过在show
的结果上调用printGrade
来解决这个问题(我建议你重命名该函数,因为函数不打印任何东西),这样我们就可以转换{ {1}}输入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))
函数中使用case
,但实际上并未执行任何模式匹配。我们可以使用 guards ,例如:
printGrade
因此,我们在每个案例中使用一个警卫,而且不需要检查该值是否例如小于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"
,因为在这种情况下,前一个警卫会被解雇。
我们可以对0
函数使用相同的技术:使用模式和保护来匹配值:
note