我正在尝试在Haskell中创建一个我认为非常直观的方法。我有一个列表[列表] *列表,任意深入。无论递归的深度如何,我都想在列表中提取一个特定的原子。这是我的努力:
type List = [Array]
data Array = Int | List
drill :: Array -> [Int] -> Array
drill xs (index:[]) = xs !! index
drill xs (index:is) = drill (xs !! index) is
但是在ghci中加载时会收到以下内容:
drill.hs:5:23:
Couldn't match expected type `[Array]' with actual type `Array'
In the first argument of `(!!)', namely `xs'
In the expression: xs !! index
In an equation for `drill': drill xs (index : []) = xs !! index
我写的内容对我来说似乎很直观,但显然Haskell有类型问题。作为一个Haskell新手,我不是最好的解释类型错误。我认为函数的返回类型可以是原子:Int
,也可以是列表:[Int]
。任何人都可以帮我解读这个并提出解决方案吗?
答案 0 :(得分:16)
当你说
时data Array = Int | List
这并不意味着“任何Int
都是Array
,任何List
都是Array
”。相反,它意味着Array
有两个构造函数Int
和List
,两者都不带参数。混淆源于它们与类型同名的事实;它们与共享名称之外的类型无关。也就是说,您的声明与
data Array = Foo | Bar
相反,我们需要为每个替代方案提供明确的构造函数名称:
type List = [Array]
data Array = Elem Int | Nest List
drill :: Array -> [Int] -> Array
drill xs [] = xs
drill (Nest xs) (index:is) = drill (xs !! index) is
这意味着Elem
需要Int
并返回Array
,Nest
需要List
并返回Array
。我们必须调整drill
函数,以明确地从Arrays
案例中获取Nest
列表。
您收到的错误基本上是说您尝试将xs
用作列表,但它是Array
。这是因为你根本没有模式匹配:只是试图直接使用你的参数(Array
)作为列表。
请注意,您仍需要对drill
的结果进行显式模式匹配,以确定它是单个元素还是嵌套列表。没有办法在Haskell中创建一个类型,其值可以 整数或嵌套列表; Haskell的联合是标记的(即构造函数是显式的),它没有子类型。
有关详细信息,建议您从this introduction to algebraic data types阅读Learn You a Haskell。