为什么 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 = Charb = 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,而不是最外层。

我猜你犯了两个错误:一个小错误,一个小错误。

  1. 要使用带有字母的变量(例如const)作为运算符,必​​须将其括在反引号中:

    "hello" `const` 1 = "hello"
    "hello" const 1 -- nonsense
    
  2. 你部分混淆了 foldrfoldl:

    foldr (#) n [1..3] = 1 # (2 # (3 # n))
    foldl (#) b [1..3] = ((b # 1) # 2) # 3
    

确实,foldlconst 搭配使用效果很好:

foldl const 0 "tacos"
  = ((((0 `const` t) `const` a) `const` c) `const` o) `const` s
  = 0

这种愚蠢的计算相当低效——它需要遍历整个列表以将 const 0 应用到每个元素,即使结果总是相同!