我想typeCheck
两个numberList
。这会导致无限循环。解决我的问题有哪些解决方案?
data Type =
Function Type Type |
Number |
Tuple [Type] |
Limited [Type]
deriving (Show, Eq)
-- type x is of type y
typeCheck :: Type -> Type -> Bool
typeCheck x y = case y of
Function ya yr -> case x of
Function xa xr -> typeCheck xa ya && typeCheck xr yr
_ -> False
Number -> x == Number
Tuple ys -> case x of
Tuple xs | length xs == length ys ->
all (==True) $ zipWith typeCheck xs ys
_ -> False
Limited ys -> case x of
Limited xs | length ys >= length xs ->
all (==True) $ zipWith typeCheck xs ys
_ -> any (==True) $ map (typeCheck x) ys
{-
- A list of numbers can be represented as follows
- () empty list
- (1, ()) [1]
- (1, (2, (3, ()))) [1,2,3]
-}
numberList = Limited [ Tuple [], Tuple [ Number, numberList ] ]
答案 0 :(得分:9)
问题是你通过结构递归,直到你到达Tuple
的最后一个元素,最后再次减少到typeCheck numberList numberList
;一个明显的无限递归。如果您希望能够检查它们是否相等,则必须重新构建数据类型以明确表示 这种循环。例如,您可以添加绑定表单,例如
Recursive "numberList" $ Limited [Tuple [], Tuple [Number, Var "numberList"]]
或者,使用De Bruijn indices(更容易以编程方式处理,为人类写作更尴尬):
Recursive $ Limited [Tuple [], Tuple [Number, Var 0]]
这需要你在typeChecks
中随身携带一个堆栈,以便你可以检测到它。
typeChecks' [("numberList", ...)] (Var "numberList") (Var "numberList")
并将其解析为True
。
顺便说一句,all (==True)
≡all id
≡and
; any (==True)
≡any id
≡or
。
顺便提一下,通过使用模式匹配和手动递归length
函数可以大规模简化您的函数并避免大多数额外的typeChecks
检查,以确保两个列表具有相同的长度:
typeCheck :: Type -> Type -> Bool
typeCheck (Function as rs) (Function as' rs') =
typeChecks as as' && typeChecks rs rs'
typeCheck Number Number = True
typeCheck (Tuple xs) (Tuple ys) = typeChecks xs ys
typeCheck x@(Limited xs) (Limited ys)
| length ys >= length xs = and $ zipWith typeCheck xs ys
| otherwise = any (typeCheck x) ys
typeCheck _ _ = False
typeChecks :: [Type] -> [Type] -> Bool
typeChecks [] [] = True
typeChecks (x:xs) (y:ys) = typeCheck x y && typeChecks xs ys
typeChecks _ _ = False