如何测试递归结构的相等性?

时间:2012-01-06 10:32:41

标签: haskell

我想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 ] ]

1 个答案:

答案 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 idand; any (==True)any idor

顺便提一下,通过使用模式匹配和手动递归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