Интерфейс Python определяет для вас распознаватели is_cons
, is_nil
, которые затем можно использовать для упрощения кода. Что-то вроде:
from z3 import *
List = Datatype('List')
List.declare('cons', ('car', IntSort()), ('cdr', List))
List.declare('nil')
List = List.create()
# constructors
cons = List.cons
car = List.car
cdr = List.cdr
nil = List.nil
# recognizers
def is_cons (x): return simplify(List.is_cons(x))
def is_nil (x): return simplify(List.is_nil(x))
def valToConstructor(l):
if is_cons(l):
return "Found cons"
elif is_nil(l):
return "Found nil"
else:
raise Exception('Unexpected list value: {}'.format(l))
# example:
ex1 = nil
ex2 = cons (0, cons (1, ex1))
print valToConstructor(ex1)
print valToConstructor(ex2)
При запуске это выдает:
Found nil
Found cons
Обратите внимание, что вы не можете пропустить исключительную ситуацию в valToConstructor
, поскольку эта функция также может вызываться с символическим значением; и распознаватели не будут стрелять в эти ценности. Но если вы всегда называете это значениями, которые вы получаете из модели, это должно работать просто отлично.
Прямой доступ к конструктору
Вы также можете использовать функцию decl
для базового AST:
>>> ex1.decl()
nil
>>> ex2.decl()
cons
Но вы должны быть осторожны, когда объект, который вы передаете, является символическим значением; как в этом случае decl
возвращает свое имя:
>>> ex3 = Const('ex3_name', List)
>>> ex3.decl()
ex3_name
Но, возможно, это именно то, что вы ищете.