kdrag.reflect.reflect
- kdrag.reflect.reflect(f, globals=None, by=[]) FuncDeclRef
Reflect a function definition by injecting the parameters and recursive self call into the local environment. Uses type annotations to do so.
Only handles a purely functional subset of python. Simple assignment is handled as a let who’s scope extends to the end of it’s subbranch. Every branch must end with a return.
You can still call original function under attribute __wrapped__.
>>> def foo(x : int) -> int: ... return x + 3 >>> foo = reflect(foo) >>> foo.__wrapped__(3) 6 >>> foo.defn |= ForAll(x, foo(x) == x + 3)
>>> @reflect ... def bar(x : int, y : str) -> int: ... if x > 4: ... return x + 3 ... elif y == "fred": ... return 14 ... else: ... return bar(x - 1, y) >>> bar.defn |= ForAll([x, y], bar(x, y) == If(x > 4, x + 3, If(y == "fred", 14, bar(x - 1, y)))) >>> @reflect ... def buzzy(n: int) -> int: ... if n == 0: ... assert n == 0 ... x = 1 ... y = x ... else: ... y = 2 ... return y >>> @reflect ... def coverage(x : int) -> int: ... if x + 1 > x: ... return x >>> z = smt.Int("z") >>> @reflect ... def inc_78(n: int, m : "smt.Lambda([z], smt.And(z > 0, z > n))") -> "smt.Lambda([z], z > n)": ... return n + m >>> #test_match54.defn >>> @reflect ... def test_add32(x : kd.Nat, y : kd.Nat) -> kd.Nat: ... match x: ... case S(n): ... return kd.Nat.S(test_add32(n, y)) ... case Z(): ... return y >>> test_add32.defn |= ForAll([x, y], test_add32(x, y) == If(is(S, x), S(test_add32(pred(x), y)), y)) >>> @reflect ... def test_match54(x: "int", y: int) -> int: ... match x: ... case 0: ... return y ... case _ if y > 0: ... return y + 1 ... case _: ... return y - 1 >>> test_match54.defn |= ForAll([x, y], test_match54(x, y) == If(x == 0, y, If(y > 0, y + 1, y - 1))) >>> @reflect ... def test_false_pre(x: smt.Lambda([z], z != z)) -> int: ... assert False ... return 42 >>> @reflect ... def test_false_match(x: int)-> int: ... match x: ... case 4: ... return x ... case 4: ... assert False ... return x ... case _: ... return x >>> @reflect ... def test_false_if(x: int, p : "smt.ExprRef # x > 0") -> "x > -1": ... return () >>> @reflect ... def test_set_notation(x : "{x for x in int if x > 0}") -> "{y for y in int if y > x and y > 0}": ... return x + 1 >>> test_set_notation.contract |= ForAll(x, Implies(And(x > 0), Implies(And, And(And(And(test_set_notation(x) > x, test_set_notation(x) > 0)))))) >>> myconst = kd.define("myconst12345", [], smt.IntVal(42)) >>> @reflect ... def test_proof_call() -> "{y for y in int if y == myconst}": ... if myconst != 42: ... () = myconst.defn ... assert False ... return 0 ... else: ... return 42 >>> test_proof_call.contract |= Implies(And, And(And(test_proof_call == myconst12345))) >>> @reflect ... def test_tuple(x : tuple[int, tuple[bool, int]]) -> bool: ... (_, (b, y)) = x ... return b >>> @reflect ... def test_forloop(x : int) -> "{y for y in int if y == x + 6}": ... for i in range(4): ... x = x + i ... return x
- Return type:
FuncDeclRef