You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

检查BinTree的Applicative同态律时QuickCheck返回0测试的解决办法

解决QuickCheck验证BinTree Applicative同态律时返回0测试的问题

我希望验证自定义数据类型BinTree的Applicative同态律是否成立,编写了如下Haskell代码,但执行时QuickCheck返回(0 tests),无法完成测试:

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE AllowAmbiguousTypes #-} 
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}

module Laws where

import Control.Applicative ((<$>), liftA3)

import Data.Monoid

import Test.QuickCheck
import Test.QuickCheck.Function
import Test.QuickCheck.Gen

data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Show, Eq)

instance Functor BinTree where
    fmap _ Empty = Empty
    fmap f (Node x hi hd) = Node (f x) (fmap f hi) (fmap f hd)

instance Applicative BinTree where
    -- pure :: a -> BinTree a
    pure x = Node x (pure x) (pure x)

    -- <*> :: BinTree (a -> b) -> BinTree a -> BinTree b
    _ <*> Empty = Empty -- L1, 
    Empty <*> t = Empty
    (Node f l r) <*> (Node x l' r') = Node (f x) (l <*> l') (r <*> r')

instance (Arbitrary a) => Arbitrary (BinTree a) where
    arbitrary = oneof [return Empty, -- oneof :: [Gen a] -> Gen a
                liftA3 Node arbitrary arbitrary arbitrary]
                
-- Identity
apIdentityProp :: (Applicative f, Eq (f a)) => f a -> Bool
apIdentityProp v = (pure id <*> v) == v

apHomomorphismProp :: forall f a b. (Applicative f, Eq (f b)) => Fun a b -> a -> Bool
apHomomorphismProp (apply -> g) x = (pure @f g <*> pure x) == pure (g x)

main = quickCheck $ apHomomorphismProp @BinTree @Int @Int

执行后得到的错误输出:

(0 tests)

问题根源

核心问题在于BinTree的Applicative实例中pure的定义是无限递归的:

pure x = Node x (pure x) (pure x)

这个定义会生成无限嵌套的树结构,QuickCheck无法生成、处理或比较这种无限数据,导致测试无法启动,直接返回0测试结果。

解决方案

修改pure的定义,让它生成有限的BinTree,比如创建一个仅包含根节点、左右子树为空的树:

instance Applicative BinTree where
    -- 改为有限结构的pure
    pure x = Node x Empty Empty
    -- 保持<*>的逻辑不变
    _ <*> Empty = Empty
    Empty <*> t = Empty
    (Node f l r) <*> (Node x l' r') = Node (f x) (l <*> l') (r <*> r')

修改后,QuickCheck就能正常生成测试用例,执行同态律的验证了。

补充说明

如果必须使用无限结构的pure,则需要自定义针对无限递归类型的相等性判断(比如只比较有限深度的结构),或者使用有限近似的生成器,但这会大幅增加代码复杂度。因此最简洁可靠的方案是让pure生成有限树。

内容的提问来源于stack exchange,提问作者F. Zer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:45:24