Haskell 不同类型的类型签名

Haskell type signatures with different types

我正在尝试创建一个函数,该函数接受项目列表和 returns A) 形式的元组的列表 (2, "X") 如果项目 "X" 连续出现两次,或者 B) 项目本身,如果它不与重复项相邻。

示例:

encode ["A", "A", "A", "B", "C", "C", "B", "B", "B", "D"]
> [(3, "A"), "B", (2, "C"), (3, "B"), "D"]

合适的类型签名是什么?我试过这个:

data listItem a = (Integer, a) | a
encode :: (Eq a) => [a] -> [listItem a]

但是我得到这个错误:

parse error in constructor in data/newtype declaration: (Integer, a) 

我偷看了这个问题的解决方案,它给了我这个类型签名:

data ListItem a = Single a | Multiple Int a
    deriving (Show)
encode :: Eq a => [a] -> [ListItem a]

但是当使用这个简单的测试时

encode [x] = [x]

我得到一个错误:

Could not deduce (a ~ ListItem a)
from the context (Eq a)
  bound by the type signature for
             encode :: Eq a => [a] -> [ListItem a]
  at 99problems.hs:117:19-45
  `a' is a rigid type variable bound by
      the type signature for
        encode :: Eq a => [a] -> [ListItem a]
      at 99problems.hs:117:19
In the expression: x
In the expression: [x]

这个问题的正确类型签名是什么?

据我了解,“99 题”集最初是为 Prolog 编写的,然后翻译成 Lisp。就是那时……啊……音译为Haskell。不幸的是,在 Lisp 中有意义的事情在 Haskell 中并不总是那么有意义,因此过于字面地理解问题描述会给您带来麻烦。提示告诉你的是,与其尝试编写一个生成像 [(3, "A"), "B", (2, "C"), (3, "B"), "D"] 这样的列表的函数,这在 Haskell 中是根本不可能的,你应该致力于生成一个看起来像 [Multiple 3 "A", Single "B", Multiple 2 "C", Multiple 3 "B", Single "D"] 的列表.

建议的类型签名正确;你只需要编写代码来匹配它。

备注

正如我所说,99 道习题集并不是很 Haskellian。它完全不尊重 Haskell 代码 的惯用风格 ,因此您应该 而不是 将其作为如何编写 Haskell 代码。例如,一个 Haskell 程序员(或者,就此而言,一个理智的 Lisp 程序员)可能只会生成一个 (Int,a) 对的列表,而不会理会那些 single/multiple 使一切变得毫无意义的废话更复杂,更不统一,并且在实际应用程序中很可能更慢。

“99 个问题”往往会打破 Haskell 编程的通常预期:

  1. 它倾向于按照与 Haskell 程序员不同的顺序放置参数。如果一个函数接受一个列表和一个数字,Haskell 程序员几乎总是把数字放在第一位,列表放在第二位; “99题”往往反过来。

  2. Haskell 程序员几乎总是对列表、数组等使用从 0 开始的索引。“99 题”似乎喜欢从 1 开始的索引。