我有以下代码,使用this tabulation library:
{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}
import ClassyPrelude
import qualified Text.Tabular as T
data Category = Age | Gender | Usual | Years
deriving (Show, Read, Eq, Enum, Bounded)
tabulate :: Text -> [[Int]] -> T.Table (T.Header Int) (T.Header Text) Int
tabulate lbl tab = T.Table (T.Group T.NoLine (map T.Header leftcoll)) (T.Group T.DoubleLine [T.Header lbl, T.Header "All", T.Header "Cluster0", T.Header "Cluster1"]) rest
where leftcoll = map (`indexEx` 0) tab
rest = map (drop 1) tab
当我尝试编译它时,我收到以下错误:
Couldn't match type ‘Int’ with ‘T.Header Int’
Expected type: [T.Header Int]
Actual type: [Int]
In the second argument of ‘map’, namely ‘leftcoll’
In the second argument of ‘T.Group’, namely
‘(map T.Header leftcoll)’
Couldn't match expected type ‘T.Header Text’
with actual type ‘Text’
In the first argument of ‘T.Header’, namely ‘lbl’
In the expression: T.Header lbl
我完全不知道为什么会这样。从the Table type documentation and example开始,我似乎只需要将Header
构造函数应用于值列表,然后将它们放在Group
构造函数中以获取整行(或列)值,但是那里的错误似乎表明我作为参数传递给Header
构造函数的列表(和数据)已经需要Header
s。因此,我对类型系统在这里告诉我什么以及如何得到我想要的东西感到困惑。
基本上,表格看起来应该是这样的:
Foo All Cluster0 Cluster1
=========================
1 10 3 7
2 11 10 1
....
答案 0 :(得分:1)
我花了一段时间才找到这个,因为你的函数定义没有问题:它是错误的类型声明。
让我们来看看Table
的定义:
data Table rh ch a = Table (Header rh) (Header ch) [[a]]
列标题和行标题类型参数已在Header
类型中变形,因此无需再次执行此操作。
而不是定义:
tabulate :: Text -> [[Int]] -> T.Table (T.Header Int) (T.Header Text) Int
你可以定义:
tabulate :: Text -> [[Int]] -> T.Table Int Text Int
为了调试这类事情,我通常会将表达式的一部分提取到where子句,以及一个类型注释,告诉编译器每个表达式应该是什么。这通常会让我得到更好的错误消息。例如,在这里,我提取了:
where tagada :: [T.Header Int]
tagada = map T.Header leftcoll
在错误中,我可以阅读:
Expected type: [T.Header (T.Header Int)]
Actual type: [T.Header Int]
当我意识到Header
类型可能被使用了两次时。