(Haskell) Can't understand error : No instance for (Ord a) arising from a use of ‘’
(Haskell) Can't understand error : No instance for (Ord a) arising from a use of ‘’
我正在尝试编写一个函数,该函数接受一个字符串列表(包含要在元组内的列表上执行的操作)和一个包含 2 个 Int 列表的元组作为参数 (testReturn)。
该函数应该对 Int 列表执行操作,检查元组中的第一个列表是否按升序排列,然后 returns 一个布尔值取决于结果。
此代码无法编译,我不确定一些事情。
我的代码:
testReturn :: [[Char]] -> ([a], [b]) -> Bool
testReturn [] b = orderedCheck $ fst b
testReturn (a:as) b
| a == "sa" = testReturn as (saFunc $ fst b, snd b)
orderedCheck :: (Ord a) => [a] -> Bool
orderedCheck [] = True
orderedCheck [x] = True
orderedCheck (x:y:xs) = x <= y && orderedCheck (y:xs)
saFunc :: [a] -> [a]
saFunc x
| length x <= 1 = x
saFunc (x:y:xs) = (y:x:xs)
我知道 orderedCheck 和 saFunc 函数有效
我担心的是:
- [[Char]] : 不知道这样写对不对,也不确定是不是真正的字符串列表。
- orderedCheck $ fst b :这是我遇到 GHC 错误的部分:“(Ord a) 没有因使用‘orderedCheck’而产生的实例”,我环顾四周,我无法理解是什么意思是
- 我在别处听说 fst 和 snd 的使用可能有点急躁(是吗?),但我不知道没有它怎么办。
你们能帮我理解我的错误以修复我的代码吗?
谢谢!
- [[Char]] : Not sure if writing this is right or not, and not sure if it really means a list of strings.
是的,它确实表示一个字符串列表——即类型[String]
。这与 [[Char]]
相同,因为在 Haskell 中,String
和 [Char]
是类型同义词,从字面上看是指代完全相同事物的不同方式。因此,在每个方括号中加上一对方括号(表示该类型的列表)也会导致两个等价类型。
在编写 Haskell 代码时,String
通常被认为比 [Char]
更地道,但这没什么大不了的。 (即使你在任何地方都使用 String
,编译器在报告错误时可能仍然使用 [Char]
,所以了解这种等价性很重要。)
- orderedCheck $ fst b : this is the part where I have a GHC error : "No instance for (Ord a) arising from a use of ‘orderedCheck’ ",I looked around and I can't understand what does it mean.
正如@Ismor 在评论中所说的那样 - 但由于我在回答中有更多 space,我将尝试给出稍微更长、更清晰的解释。
您正在使用值 fst b
调用 orderedCheck
。根据你自己的(正确的)类型签名,orderedCheck
的类型为 (Ord a) => [a] -> Bool
。这意味着它的参数必须是一个列表,其元素的类型 a
满足约束 Ord a
.
但是您在 testReturn
中的 fst b
上使用它。 b
是函数的第二个参数,从它的类型签名来看,它的类型必须是 ([a], [b])
。这意味着 fst b
必须是 [a]
类型——这是一个列表,到目前为止还不错。但是正如刚才提到的,那个类型 a
必须有一个 Ord
的实例。不幸的是,我们不能保证这一点,因为您的类型签名 - [[Char]] -> ([a], [b]) -> Bool
- 允许 a
和 b
绝对是任何东西。如果此代码已编译,该类型签名将允许我调用该函数,例如 testReturn ["Example"] ([putStrLn "foo"], [])
- 但 putStrLn "foo"
具有类型 IO ()
,它肯定没有 Ord
实例. (除非你在你的代码中提供一个,这听起来不是一个好主意 - 但即使你这样做了,你也可以很容易地找到另一种没有 Ord
实例的类型,这会导致同样的问题。)
解决此问题的唯一方法是修复 testReturn
的类型签名 - 它实际上不能接受任何类型作为 a
,因为该类型必须具有 Ord
实例。所以包括这个要求,你会没事的:
testReturn :: (Ord a) => [[Char]] -> ([a], [b]) -> Bool
(正如@MarkSeemann 指出的那样,如果您遗漏了任何类型签名,这正是 GHC 会为您推断出的签名。我当然不建议为顶级函数保留类型签名,但如果您如果您不确定签名应该是什么,这种将其省略然后让 GHCi 使用 :t
为您推断的技术几乎可以保证给您想要的东西。)
- I heard somewhere else that the use of fst and snd may be a bit edgy (is it?), but I don't know how to do without it.
我不确定在这种情况下“前卫”是什么意思。它当然不是“错误的”,也不像 head
和 tail
用于列表那样危险——当给定一个空列表时,这些函数将崩溃(在运行时),而 fst
和 snd
适用于任何二元组(如果给定的值不是二元组,您的代码将无法编译 - 因此运行时崩溃的风险为零)。
但是,与模式匹配相比,它不是很优雅,这里更像是其他语言中的“解构”。我认为大多数 Haskell 用户会像这样编写您的函数,这等同于您的代码并且希望不言自明:
testReturn [] (b, _) = orderedCheck b
testReturn (a:as) (b, c)
| a == "sa" = testReturn as (saFunc b, c)
(请注意,此函数似乎不完整,如果使用第一个元素不是 "sa"
的非空第一个参数调用,将会崩溃。)
我正在尝试编写一个函数,该函数接受一个字符串列表(包含要在元组内的列表上执行的操作)和一个包含 2 个 Int 列表的元组作为参数 (testReturn)。 该函数应该对 Int 列表执行操作,检查元组中的第一个列表是否按升序排列,然后 returns 一个布尔值取决于结果。
此代码无法编译,我不确定一些事情。
我的代码:
testReturn :: [[Char]] -> ([a], [b]) -> Bool
testReturn [] b = orderedCheck $ fst b
testReturn (a:as) b
| a == "sa" = testReturn as (saFunc $ fst b, snd b)
orderedCheck :: (Ord a) => [a] -> Bool
orderedCheck [] = True
orderedCheck [x] = True
orderedCheck (x:y:xs) = x <= y && orderedCheck (y:xs)
saFunc :: [a] -> [a]
saFunc x
| length x <= 1 = x
saFunc (x:y:xs) = (y:x:xs)
我知道 orderedCheck 和 saFunc 函数有效
我担心的是:
- [[Char]] : 不知道这样写对不对,也不确定是不是真正的字符串列表。
- orderedCheck $ fst b :这是我遇到 GHC 错误的部分:“(Ord a) 没有因使用‘orderedCheck’而产生的实例”,我环顾四周,我无法理解是什么意思是
- 我在别处听说 fst 和 snd 的使用可能有点急躁(是吗?),但我不知道没有它怎么办。
你们能帮我理解我的错误以修复我的代码吗? 谢谢!
- [[Char]] : Not sure if writing this is right or not, and not sure if it really means a list of strings.
是的,它确实表示一个字符串列表——即类型[String]
。这与 [[Char]]
相同,因为在 Haskell 中,String
和 [Char]
是类型同义词,从字面上看是指代完全相同事物的不同方式。因此,在每个方括号中加上一对方括号(表示该类型的列表)也会导致两个等价类型。
String
通常被认为比 [Char]
更地道,但这没什么大不了的。 (即使你在任何地方都使用 String
,编译器在报告错误时可能仍然使用 [Char]
,所以了解这种等价性很重要。)
- orderedCheck $ fst b : this is the part where I have a GHC error : "No instance for (Ord a) arising from a use of ‘orderedCheck’ ",I looked around and I can't understand what does it mean.
正如@Ismor 在评论中所说的那样 - 但由于我在回答中有更多 space,我将尝试给出稍微更长、更清晰的解释。
您正在使用值 fst b
调用 orderedCheck
。根据你自己的(正确的)类型签名,orderedCheck
的类型为 (Ord a) => [a] -> Bool
。这意味着它的参数必须是一个列表,其元素的类型 a
满足约束 Ord a
.
但是您在 testReturn
中的 fst b
上使用它。 b
是函数的第二个参数,从它的类型签名来看,它的类型必须是 ([a], [b])
。这意味着 fst b
必须是 [a]
类型——这是一个列表,到目前为止还不错。但是正如刚才提到的,那个类型 a
必须有一个 Ord
的实例。不幸的是,我们不能保证这一点,因为您的类型签名 - [[Char]] -> ([a], [b]) -> Bool
- 允许 a
和 b
绝对是任何东西。如果此代码已编译,该类型签名将允许我调用该函数,例如 testReturn ["Example"] ([putStrLn "foo"], [])
- 但 putStrLn "foo"
具有类型 IO ()
,它肯定没有 Ord
实例. (除非你在你的代码中提供一个,这听起来不是一个好主意 - 但即使你这样做了,你也可以很容易地找到另一种没有 Ord
实例的类型,这会导致同样的问题。)
解决此问题的唯一方法是修复 testReturn
的类型签名 - 它实际上不能接受任何类型作为 a
,因为该类型必须具有 Ord
实例。所以包括这个要求,你会没事的:
testReturn :: (Ord a) => [[Char]] -> ([a], [b]) -> Bool
(正如@MarkSeemann 指出的那样,如果您遗漏了任何类型签名,这正是 GHC 会为您推断出的签名。我当然不建议为顶级函数保留类型签名,但如果您如果您不确定签名应该是什么,这种将其省略然后让 GHCi 使用 :t
为您推断的技术几乎可以保证给您想要的东西。)
- I heard somewhere else that the use of fst and snd may be a bit edgy (is it?), but I don't know how to do without it.
我不确定在这种情况下“前卫”是什么意思。它当然不是“错误的”,也不像 head
和 tail
用于列表那样危险——当给定一个空列表时,这些函数将崩溃(在运行时),而 fst
和 snd
适用于任何二元组(如果给定的值不是二元组,您的代码将无法编译 - 因此运行时崩溃的风险为零)。
但是,与模式匹配相比,它不是很优雅,这里更像是其他语言中的“解构”。我认为大多数 Haskell 用户会像这样编写您的函数,这等同于您的代码并且希望不言自明:
testReturn [] (b, _) = orderedCheck b
testReturn (a:as) (b, c)
| a == "sa" = testReturn as (saFunc b, c)
(请注意,此函数似乎不完整,如果使用第一个元素不是 "sa"
的非空第一个参数调用,将会崩溃。)