我试图建立一个递归函数来帮助我解决Haskell中的Project Euler problem 15(我对它很新),但编译器告诉我:
Occurs check: cannot construct the infinite type: t ~ [t]
Relevant bindings include
grid :: t (bound at 15.hs:1:22)
r :: t (bound at 15.hs:1:17)
d :: t (bound at 15.hs:1:15)
generateTree :: [t] -> t -> [t] (bound at 15.hs:1:1)
In the expression: generateTree [d + 1, r] grid
In the expression:
[generateTree [d + 1, r] grid, generateTree [d, r + 1] grid]
我不太确定这些问题是什么,而且我遇到编译器以更容易理解的方式抱怨我。这是我的功能:
generateTree (d:r:_) grid
| down && right = [generateTree [d + 1, r] grid, generateTree [d, r + 1] grid]
| down = [generateTree [d + 1, r] grid, -1]
| right = [-1, generateTree [d, r + 1] grid]
| otherwise = [d, r]
where down = elem d [0..grid]
right = elem r [0..grid]
由于
答案 0 :(得分:3)
您之所以看到错误的原因是您试图说generateTree
返回[-1, [-1, [-1, 0]]]
之类的值,而[[[-1]], [[-1], [-1, 0]]]
没有有效的类型哈斯克尔。列表中的所有值必须具有相同的类型,这意味着列表不能像这样嵌套。你可以像[[[Int]]]
一样嵌套它,但是它的类型为data Tree a = Leaf a | Node (Tree a) (Tree a) deriving (Eq, Show)
,这意味着它只能是3级深度。您需要任意嵌套的级别,因此您需要一种定义这种递归结构的新数据类型。
由于您的函数只返回列表中的两个元素,因此您可以使用二叉树执行此操作。幸运的是,这在Haskell中非常简单:
Leaf a
此处Node left right
表示单个值,而Node
(Leaf (-1))
(Node
(Leaf (-1))
(Node
(Leaf (-1))
(Leaf 0)
)
)
表示树中的拆分,因此您可以
[-1, [-1, [-1, 0]]]
(为了清晰起见,添加了空格)
这相当于generateTree :: Int -> Int -> Int -> Tree Int
generateTree d r grid
| down && right = ...
| down = ...
| right = Node (Leaf (-1)) (generateTree d (r + 1) grid)
| otherwise = Node (Leaf d) (Leaf r)
where
down = d `elem` [0..grid]
right = r `elem` [0..grid]
上面的无效列表。这更详细吗?当然,但它允许任意嵌套。
现在您只需修改函数定义即可使用此类型:
{{1}}
我将让你完成定义的其余部分,这只是一个让你入门的例子。
答案 1 :(得分:1)
您的generateTree
函数返回一个列表,请参阅:
| otherwise = [d, r]
但是d
和r
的类型是什么? generateTree
返回generateTree
函数返回的列表(列表中的所有元素必须是同一类型):
| right = [-1, generateTree [d, r + 1] grid]
换句话说,你的逻辑被打破了。学习类型系统,学会编写类型然后错误就会变得明显。