我开始学习一些编程,并且进行了以下练习:
“创建一个名为divisors的函数,该函数采用整数n> 1,并返回一个数组,该数组具有从最小到最大的所有整数除数(除了1和数字本身)。如果数字是素数,则返回字符串“(整数)为素数”。 提示:使用除数::(Show a,Integral a)=> a->任一字符串[a] “
我还不了解如何使用Either类型,因此在此期间,我决定开始逐步解决问题。
由于练习的一部分需要构造一个函数以区分质数和非质数,因此我决定首先创建一个临时函数:如果数字(a)不是质数,则必须显示其除数的列表[1..a]。如果数字(a)为质数,则必须显示字符串“(a)为质数”。
以下代码有效:
divisors a = if length [i | i <- [1..a], mod a i == 0 ] > 2
then show [i | i <- [1..a], mod a i == 0 ]
else show a ++ " is prime"
此功能的一些输出是:
[1 of 1] Compiling Main ( program.hs, interpreted )
Ok, one module loaded.
*Main> divisors 1
"1 is prime"
*Main> divisors 2
"2 is prime"
*Main> divisors 3
"3 is prime"
*Main> divisors 4
"[1,2,4]"
*Main> divisors 5
"5 is prime"
*Main> divisors 6
"[1,2,3,6]"
*Main> divisors 7
"7 is prime"
但是,我确实需要将列表显示为列表[1..a],而不是字符串“ [1..a]”。因此,我从(然后)语句中删除了(显示):
divisors a = if length [i | i <- [1..a], mod a i == 0 ] > 2
then [i | i <- [1..a], mod a i == 0 ]
else show a ++ " is prime"
但这会引发错误:
program.hs:11:42: error:
* No instance for (Integral Char) arising from a use of `mod'
* In the first argument of `(==)', namely `mod a i'
In the expression: mod a i == 0
In a stmt of a list comprehension: mod a i == 0
|
11 | divisors a = if length [i | i <- [1..a], mod a i == 0 ] > 2
| ^^^^^^^
Failed, no modules loaded.
我不完全了解出了什么问题,需要有人解释如何将非素数输出显示为列表,而不是列表的字符串表示形式。
如果有人愿意解释如何重新构造我的函数以正确使用Either类型,我不介意有人要解释如何回答解决方案中使用Either类型的原始练习问题。
编辑: 阅读一些回复后,我尝试了以下操作:
divisors :: (Show a, Integral a) => a -> Either String [a]
divisors a = if length [i | i <- [2..a], mod a i == 0] > 1
then Right [i | i <- [2..a-1], mod a i == 0]
else Left (show a ++ " is prime")
它似乎正在工作!
谢谢你的建议。
答案 0 :(得分:5)
来自@RobinZigmond:您已经发现了为什么需要Either
。 Haskell具有强大的静态类型系统,并且函数需要返回特定类型的值。函数不可能按照您想要的方式在某些输入上返回字符串,而在其他输入上返回整数列表(就像在动态语言中那样)。但这就是Either
的目的。类型Either a b
的值为Left x
,其中x
是类型a
的值,或者Right y
,其中y
是类型的值b
。希望您现在能明白为什么这对您的案件有用。
来自@chi:构造
if condition then x else y
要求x
和y
属于同一类型。如果不是,请说:
x :: TypeX
y :: TypeY
您可以将它们都转换为Either TypeX TypeY
,如下所示:
if condition then Left x else Right y
由于现在两个if
分支具有相同的类型Either TypeX TypeY
,因此它进行类型检查,并且该类型将是if
所产生的值的类型。
从原始发帖人@nutbunny:阅读一些回复后,我尝试了以下操作:
divisors :: (Show a, Integral a) => a -> Either String [a]
divisors a = if length [i | i <- [2..a], mod a i == 0] > 1
then Right [i | i <- [2..a-1], mod a i == 0]
else Left (show a ++ " is prime")
它似乎正在工作!
谢谢你的建议!