Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Haskell和SBV理解列表的条件_Haskell_Sbv - Fatal编程技术网

使用Haskell和SBV理解列表的条件

使用Haskell和SBV理解列表的条件,haskell,sbv,Haskell,Sbv,我想写一个关于符号表达式(SBV)条件的Haskell列表理解。我用下面的小例子再现了这个问题 import Data.SBV allUs :: [SInteger] allUs = [0,1,2] f :: SInteger -> SBool f 0 = sTrue f 1 = sFalse f 2 = sTrue someUs :: [SInteger] someUs = [u | u <- allUs, f u == sTrue] 将条件更改为fu.==sTr

我想写一个关于符号表达式(SBV)条件的Haskell列表理解。我用下面的小例子再现了这个问题

import Data.SBV

allUs :: [SInteger] 
allUs = [0,1,2]  

f :: SInteger -> SBool 
f 0 = sTrue
f 1 = sFalse
f 2 = sTrue

someUs :: [SInteger] 
someUs = [u | u <- allUs, f u == sTrue]
将条件更改为fu.==sTrue也会产生错误

<interactive>:8:27: error:
    • Couldn't match type ‘SBV Bool’ with ‘Bool’
      Expected type: Bool
        Actual type: SBool
    • In the expression: f u .== sTrue
      In a stmt of a list comprehension: f u .== sTrue
      In the expression: [u | u <- allUs, f u .== sTrue]
:8:27:错误:
•无法将类型“SBV Bool”与“Bool”匹配
预期类型:Bool
实际类型:SBool
•在表达式中:f u==sTrue
在列表的stmt中:fu.==sTrue

在表达式中:[u | u无论您的
f
还是您的
someUs
都不能像编写时那样进行符号计算。理想情况下,这些应该是类型错误,立即拒绝。这是因为符号值不能是
Eq
类的实例:为什么?因为确定符号值的相等性需要调用底层解算器;因此结果不能是
Bool
;它实际上应该是
SBool
。但是Haskell不允许在模式匹配中使用广义保护来考虑这种可能性。(这也有很好的理由,所以这并不是Haskell的错。只是这两种编程风格在一起并不能很好地工作。)

你可以问为什么SBV将符号值作为
Eq
类的一个实例。它是
Eq
实例的唯一原因是错误消息告诉你的:因为我们希望它们是
Bits
类的实例;它将
Eq
作为超类要求。但这完全是另一个讨论

基于此,如何在SBV中编写函数?以下是如何以符号样式编写
f

f::SInteger->SBool
f i=ite(i.==0)sTrue
$ite(i.==1)sFalse
$ite(i.==2)串
$sFalse—任意填充以使函数合计
丑陋,但这是唯一的写作方法,除非你想玩一些准引用的把戏

关于
someUs
:这也不是你可以直接象征性地写的东西:这被称为脊椎混凝土列表。SBV没有办法知道在单个元素上实际运行解算器的情况下你的结果列表会有多长。一般来说,你不能在脊椎混凝土上执行
过滤
之类的功能包含符号元素的te列表

解决方案是使用所谓的符号列表和有界列表抽象。这不是很令人满意,但这是避免终止问题的最佳方法:

{-# LANGUAGE OverloadedLists #-}

import Data.SBV
import Data.SBV.List
import Data.SBV.Tools.BoundedList

f :: SInteger -> SBool
f i = ite (i .== 0) sTrue
    $ ite (i .== 1) sFalse
    $ ite (i .== 2) sTrue
    $               sFalse   -- arbitrarily filled to make the function total

allUs :: SList Integer
allUs = [0,1,2]

someUs :: SList Integer
someUs = bfilter 10 f allUs
当我运行此程序时,我得到:

*Main> someUs
[0,2] :: [SInteger]
但是你会在调用
bfilter
时问这个数字
10
是多少?好吧,这个想法是假设所有列表的长度都有某种上界,然后导出一组方法来轻松处理它们;所有这些方法都使用一个绑定参数。只要输入的长度最多为这个长度,它们就可以正常工作显然,如果你的列表比给定的边界长,那么无法保证会发生什么。(一般来说,它会在边界处切掉你的列表,但你不应该依赖这种行为。)

这里有一个与BMC(有界模型检查)协作使用此类列表的示例

总而言之,由于Haskell中的限制(其中,
Bool
是一个固定类型而不是类),在符号上下文中处理列表需要一些建模成本和可以做的工作,以及无法很好地处理递归定义函数的基础解算器。后者主要是因为这样的证明需要归纳,而SMT解算器无法进行开箱即用的归纳。但如果你使用类似BMC的思想遵循游戏规则,你可以处理问题的实际实例,直到合理的bounds.

(..==)
获取两个
EqSymbolic
实例,返回一个
SBool
。在列表理解中,使用
guard
函数实现条件

下面是它的样子:

guard :: Alternative f => Bool -> f ()
guard False = empty
guard True = pure ()
对于列表,
empty
[]
,而
pure()
返回一个单例列表
[()]
。列表中任何计算结果为
False
的成员都将返回一个空列表,而不是一个单位项,将其从链的计算中排除

[True, False, True] >>= guard
= concatMap guard [True, False, True]
= concat $ map guard [True, False, True]
= concat $ [[()], [], [()]]
= [(), ()]
当上下文被展平时,第二个分支将被排除,因此它将从计算中“修剪”

这里似乎有两个问题-当您在
f
中进行模式匹配时,您正在使用
Eq
类进行比较。这就是SBV错误的来源。由于您的值非常接近,因此可以使用
select
,它获取项目列表、默认值、计算为索引的表达式,以及尝试从该列表中获取
索引
th项

您可以将
f
重写为

f :: SInteger -> SBool
f = select [sTrue, sFalse, sTrue] sFalse
第二个问题是警卫显式地查找
Bool
,但是
(.==)
仍然返回一个
SBool
。查看
数据.SBV
,您应该能够使用
unlateral
将其强制为一个常规
Bool
,该函数尝试将
SBV
值解包为一个等效的Haskell值

fromSBool :: SBool -> Bool
fromSBool = fromMaybe False . unliteral

someUs :: [SInteger]
someUs = [u | u <- allUs, fromSBool (f u)]
-- [0 :: SInteger, 2 :: SInteger]
fromSBool::SBool->Bool
fromSBool=fromMaybe False。非平行
萨默斯::[SInteger]

someUs=[u | u好的,我想我明白了问题所在。
f
的定义也隐含地将“Eq”应用于符号元素。我将看看BMC。感谢您的详细回答。
fromSBool
在这里使用不正确。因为如果值是符号的,它将返回
False
,但这并不意味着它是
False
。(您的特定示例之所以有效,是因为所有内容都足够具体。)一般来说,您只能依赖
unlateral
的结果,如果它是
Just
fromSBool :: SBool -> Bool
fromSBool = fromMaybe False . unliteral

someUs :: [SInteger]
someUs = [u | u <- allUs, fromSBool (f u)]
-- [0 :: SInteger, 2 :: SInteger]