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

如何检查symTake的UnionM类型结果是否等于具体列表?

在Grisette中检查UnionM包裹的列表与固定列表的相等性

我想检查symTake返回的UnionM [SymInteger]类型的result是否能等于[1, 2]。我可以直接检查普通符号整数列表和[1,2]的相等性,比如:

x :: SymInteger
x = "x"

y :: SymInteger
y = "y"

main :: IO ()
main = do
    print $ [x, y] .== [1, 2]

但不知道怎么对UnionM里的列表做同样的操作,而且文档说明不能直接拆箱UnionM中的内容。我的目标代码如下:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}

import Grisette

x :: SymInteger
x = "x"

y :: SymInteger
y = "y"

numbers :: [SymInteger]
numbers = [x, y]

n :: SymInteger
n = "n"

result :: UnionM [SymInteger]
result = symTake n numbers

main :: IO ()
main = do
    print $ result .== [1, 2] -- 此处会因类型不匹配报错

解决方案

要检查UnionM包裹的列表是否能等于目标列表,核心思路是遍历UnionM的所有分支,分别判断每个分支的列表与目标列表的相等性,再合并这些条件并检查是否存在可满足的情况。

可以通过以下两种方式实现:

方法1:使用fmap + merge + isSatisfiable

main :: IO ()
main = do
  -- 给UnionM的每个分支列表做相等性判断,得到UnionM SymBool
  let branchConds = fmap (.== [1, 2]) result
  -- 合并所有分支的条件,得到表示"是否存在分支满足相等"的SymBool
  let overallCond = merge branchConds
  -- 检查该条件是否可满足
  print $ isSatisfiable overallCond

方法2:使用unionWith简化代码

unionWith可以直接将UnionM a转换为UnionM b,这里用它直接生成每个分支的相等条件,再合并检查:

main :: IO ()
main = do
  let overallCond = unionWith (\lst -> lst .== [1, 2]) result
  print $ isSatisfiable $ merge overallCond

原理说明

  • symTake返回的UnionM [SymInteger]是符号执行中的分支集合,每个分支对应n取不同值时的take结果(比如n≤0时取空列表,n=1时取[x],n≥2时取[x,y])。
  • 不能直接用.==比较UnionM [SymInteger]和[SymInteger],因为类型不匹配。必须先对每个分支单独做相等判断,再通过merge将分支条件合并为一个全局的符号布尔值,最后用isSatisfiable验证是否存在变量取值让条件成立。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:53:09