为什么 foldr const 0 "tacos" 不在 Haskell 中编译?
Why doesn't foldr const 0 "tacos" Compile in Haskell?
所以 foldr const 0 "tacos"
应该会变成
0 const ('t' const ('a' const ('c' const ('o' const 's')))).
我认为它只会在 0 const ('t'
处停止,因为 Haskell 是惰性求值的,而 const 只接受第一个参数。那么,理论上,该函数不会应用于 1 吗?
虽然这不起作用。将 0
替换为 ""
也不起作用。有谁知道为什么?
谢谢!
Why doesn't foldr const 0 “tacos” Compile in Haskell?
因为:
> foldr const 0 "tacos"
<interactive>:1:13: error:
• No instance for (Num Char) arising from the literal ‘0’
• In the second argument of ‘foldr’, namely ‘0’
In the expression: foldr const 0 "tacos"
In an equation for ‘it’: it = foldr const 0 "tacos"
因此,如果我们进行调查,我们会看到(请忽略 @[]
,它是一种使我们的对话更简单的类型应用程序)
> :t foldr @[] const 0
foldr @[] const 0 :: Num b => [b] -> b
因此您需要提供 Num
个实例的项目列表。但是你提供了:
> :t "tacos"
"tacos" :: [Char]
炸玉米饼有时是裹着肉和米饭的玉米饼。但有时,比如现在,它们是字符列表。字符不是 Num
的实例。这就是错误试图告诉您的内容。
查看 foldr 的类型(让我们专注于列表):
foldr :: (a -> b -> b) -> b -> [a] -> b
您已经提供了参数(让我们专注于 Int 的 0)
const :: a -> b -> b -- this looks off...
0 :: b -- this means b = Int
"tacos" :: [a] -- this means a = Char
稍等。检查const的实际类型:
const :: a -> b -> a
看到问题了吗?您以错误的顺序获得 const
的参数。尝试 (flip const)
而不是 const
以获得所需的答案,尽管它没有所需的性能特征。
您可能还想尝试 foldl'
,它从左到右累积结果。
按照您最初编写的方式,类型系统必须统一 const 的类型签名 a -> b -> a
和 foldr 的参数类型 a -> b -> b
,这只能通过统一 a = b
来完成.然而,由于a = Char
和b = Int
,无法执行此统一。
表达式的正确 "unraveling"(foldr
的工作方式)是将 :
替换为 const
,将 []
替换为 0
.
't' : 'a' : 'c' : 'o' : 's' : []
==> let's write it with (:) as a prefix funtion
(:) 't' ((:) 'a' ((:) 'c' ((:) 'o' ((:) 's' []))))
==>
const 't' (const 'a' (const 'c' (const 'o' (const 's' 0))))
但是由于以上所有 const
必须具有相同类型的限制,它们不能。
注意 0
如何出现在 innermost const,而不是最外层。
我猜你犯了两个错误:一个小错误,一个小错误。
要使用带有字母的变量(例如const
)作为运算符,必须将其括在反引号中:
"hello" `const` 1 = "hello"
"hello" const 1 -- nonsense
你部分混淆了 foldr
和 foldl
:
foldr (#) n [1..3] = 1 # (2 # (3 # n))
foldl (#) b [1..3] = ((b # 1) # 2) # 3
确实,foldl
与 const
搭配使用效果很好:
foldl const 0 "tacos"
= ((((0 `const` t) `const` a) `const` c) `const` o) `const` s
= 0
这种愚蠢的计算相当低效——它需要遍历整个列表以将 const 0
应用到每个元素,即使结果总是相同!
所以 foldr const 0 "tacos"
应该会变成
0 const ('t' const ('a' const ('c' const ('o' const 's')))).
我认为它只会在 0 const ('t'
处停止,因为 Haskell 是惰性求值的,而 const 只接受第一个参数。那么,理论上,该函数不会应用于 1 吗?
虽然这不起作用。将 0
替换为 ""
也不起作用。有谁知道为什么?
谢谢!
Why doesn't foldr const 0 “tacos” Compile in Haskell?
因为:
> foldr const 0 "tacos"
<interactive>:1:13: error:
• No instance for (Num Char) arising from the literal ‘0’
• In the second argument of ‘foldr’, namely ‘0’
In the expression: foldr const 0 "tacos"
In an equation for ‘it’: it = foldr const 0 "tacos"
因此,如果我们进行调查,我们会看到(请忽略 @[]
,它是一种使我们的对话更简单的类型应用程序)
> :t foldr @[] const 0
foldr @[] const 0 :: Num b => [b] -> b
因此您需要提供 Num
个实例的项目列表。但是你提供了:
> :t "tacos"
"tacos" :: [Char]
炸玉米饼有时是裹着肉和米饭的玉米饼。但有时,比如现在,它们是字符列表。字符不是 Num
的实例。这就是错误试图告诉您的内容。
查看 foldr 的类型(让我们专注于列表):
foldr :: (a -> b -> b) -> b -> [a] -> b
您已经提供了参数(让我们专注于 Int 的 0)
const :: a -> b -> b -- this looks off...
0 :: b -- this means b = Int
"tacos" :: [a] -- this means a = Char
稍等。检查const的实际类型:
const :: a -> b -> a
看到问题了吗?您以错误的顺序获得 const
的参数。尝试 (flip const)
而不是 const
以获得所需的答案,尽管它没有所需的性能特征。
您可能还想尝试 foldl'
,它从左到右累积结果。
按照您最初编写的方式,类型系统必须统一 const 的类型签名 a -> b -> a
和 foldr 的参数类型 a -> b -> b
,这只能通过统一 a = b
来完成.然而,由于a = Char
和b = Int
,无法执行此统一。
表达式的正确 "unraveling"(foldr
的工作方式)是将 :
替换为 const
,将 []
替换为 0
.
't' : 'a' : 'c' : 'o' : 's' : []
==> let's write it with (:) as a prefix funtion
(:) 't' ((:) 'a' ((:) 'c' ((:) 'o' ((:) 's' []))))
==>
const 't' (const 'a' (const 'c' (const 'o' (const 's' 0))))
但是由于以上所有 const
必须具有相同类型的限制,它们不能。
注意 0
如何出现在 innermost const,而不是最外层。
我猜你犯了两个错误:一个小错误,一个小错误。
要使用带有字母的变量(例如
const
)作为运算符,必须将其括在反引号中:"hello" `const` 1 = "hello" "hello" const 1 -- nonsense
你部分混淆了
foldr
和foldl
:foldr (#) n [1..3] = 1 # (2 # (3 # n)) foldl (#) b [1..3] = ((b # 1) # 2) # 3
确实,foldl
与 const
搭配使用效果很好:
foldl const 0 "tacos"
= ((((0 `const` t) `const` a) `const` c) `const` o) `const` s
= 0
这种愚蠢的计算相当低效——它需要遍历整个列表以将 const 0
应用到每个元素,即使结果总是相同!