haskell - 在下面的示例代码上下文中,如何将函数输出显示为列表 [a],而不是字符串,show [a]

标签 haskell

我开始学习一些编程,并进行了以下练习:

“创建一个名为 divisors 的函数,它接受一个整数 n > 1 并返回一个数组,其中包含该整数的所有除数(除了 1 和数字本身),从最小到最大。如果该数字是质数,则返回字符串“(整数)是素数”。 提示:使用除数::(Show a, Integral a) => a -> Either String [a]"

我还不明白如何使用 Either 类型,因此在此期间我决定开始逐步解决这个问题。

由于练习的一部分需要构造一个函数来区分素数和非素数,因此我决定首先创建一个临时函数:如果数字 (a) 不是素数,我必须显示它的约数列表[1..a]。如果数字 (a) 是素数,我必须显示字符串“(a) is prime”。

以下代码有效:

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]”。因此,我从(then)语句中删除了(show):

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")

它似乎有效!

感谢您的建议。

最佳答案

来自@RobinZigmond:好吧,您已经发现为什么需要Either。 Haskell 具有强大的静态类型系统,函数需要返回特定类型的值。函数不可能按照您的意愿执行操作并在某些输入上返回字符串并在其他输入上返回整数列表(就像在动态语言中一样)。但这就是 Either 的用途。 a b 类型的值可以是 Left x,其中 xa 类型的值,或者 >右 y,其中 yb 类型的值。希望您现在可以明白为什么这对您的案例有用。

来自@chi:构造

if condition then x else y

要求xy具有相同的类型。如果不是,请说:

x :: TypeX
y :: TypeY

您可以将两者转换为TypeX TypeY,如下所示:

if condition then Left x else Right y

由于现在两个 if 分支具有相同的类型 TypeX TypeY,因此它会进行类型检查,并且该类型将是 生成的值的类型>如果

来自原始海报@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")

它似乎有效!

感谢您的建议!

关于haskell - 在下面的示例代码上下文中,如何将函数输出显示为列表 [a],而不是字符串,show [a],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55921004/

相关文章:

haskell - 比较 Haskell 中的函数

haskell - 如何在 GHCI 中加载优化代码?

haskell - Haskell 中不同数据类型的比较

haskell - 简化异或字符串

list - 使用 `take` 实现 Haskell 的 `foldl` 函数

haskell - 泛型系列生成无限列表

haskell - (已编辑)如何在没有 IO 的情况下在 Haskell 中获取随机数

haskell - Haskell 中的 DFS 实现

haskell - 包含不同类型的列表

haskell - 绕过预测多态性的方法