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

如何为TestIt类型编写SmallCheck的Serial实例?含依赖序列化需求

Implementing Serial for TestIt in SmallCheck

Let's break down how to solve your problem step by step, starting with the basic Serial instance and moving to dependent serialization.

1. Basic Serial Instance for TestIt

First, we need to define a Serial instance for your custom D type since SmallCheck doesn't know about it out of the box:

instance Serial m D where
  series = cons0 A \/ cons1 B \/ cons1 C
  • cons0 handles nullary constructors (like A), cons1 handles unary constructors (like B String and C String).

Next, we need to generate values of type m D for the y field's output. We can wrap our D series in pure to lift it into the monad:

instance Serial m D => Serial m (m D) where
  series = pure <$> series

Now, for the TestIt instance:
The y field is Int -> m D, which requires generating functions. SmallCheck uses the CoSerial class for this—CoSerial m a lets us generate functions from a to any serializable type. Since Int has a built-in CoSerial instance, we can use coseries to turn our m D series into a series of functions:

instance (Monad m, Serial m Int, Serial m String) => Serial m (TestIt m) where
  series = TestIt <$> xSeries <~> ySeries
    where
      xSeries = pure <$> series  -- Generate m Int by lifting Int samples into the monad
      ySeries = coseries series  -- Convert m D series into Int -> m D function series
  • <~> is SmallCheck's applicative combinator for combining series of values.

2. Dependent Serialization for y (When x is 0)

Yes, this is feasible—but it requires that your monad m lets you extract the underlying Int value from m Int. This works best with pure monads like Identity (since monads like Maybe or IO don't expose their values until runtime).

Here's how to implement this for Identity:

import Control.Monad.Identity (Identity(..))

instance Serial Identity (TestIt Identity) where
  series = do
    -- Generate the x value (Identity Int)
    xIdentity <- pure <$> series
    let intVal = runIdentity xIdentity  -- Extract the Int from Identity
    
    -- Generate y based on x's value
    yFunc <- if intVal == 0
             then -- When x is 0, generate y functions focused on input 0
                  dVal <- series :: Series Identity D
                  pure (\input -> if input == 0 then pure dVal else pure A)
             else -- Use normal function generation for other x values
                  coseries (pure <$> series)
    
    return $ TestIt xIdentity yFunc
  • We use SmallCheck's Series monad to first generate x, then conditionally generate y based on x's value.
  • When x is 0, we create functions that return a generated D value only when given 0 as input (you can adjust this logic to fit your testing needs).

Note that this approach restricts the generated TestIt instances to those where y depends on x, which is useful if you want to focus tests on the specific case where x is 0.

内容的提问来源于stack exchange,提问作者RandomB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:44:29