Skip to content
This repository has been archived by the owner on Oct 5, 2023. It is now read-only.

Consider simplifying monomorphisation and defunctionalisation #140

Open
facundominguez opened this issue Jul 25, 2022 · 2 comments
Open

Comments

@facundominguez
Copy link
Member

facundominguez commented Jul 25, 2022

I want to comment here on the approach that Liquid Haskell uses to defunctionalise and monomorphise expressions for the SMT solver. It looks to me like it is simpler than what is currently being done in pirouette. However, I'm not too familiar with pirouette yet, so I might be unaware of restrictions that render this inapplicable.

Suppose we have functions like

g :: (a -> a) -> a -> a
g f x = f x

orBool :: Bool -> Bool -> Bool
orBool True _ = True
orBool _ True = True
orBool _ _ = False

These functions can then be used in formulas, like g (orBool True) True == True && orBool True True == True.
The formulas are translated to SMTLIB2 as follows.

; functions become integer constants
(declare-fun g () Int)
(declare-fun orBool () Int)

; various uninterpreted functions are declared for applying constants
(declare-fun apply1 (Int Int) Int)
(declare-fun apply2 (Int Bool) Int)
(declare-fun apply3 (Int Bool) Bool)

; whenever a function is invoked, the apply functions are used to produce
; equations of the appropriate types
;
; translation of: g (orBool True) True == True && orBool True True == True
(assert (and (= True (apply1 g (apply2 orBool True) True)) (= True (apply3 (apply2 orBool True) True))))

When g or orBool need to be evaluated, their equations are expanded with the actual parameters

; Expand g (orBool True) True = orBool True True, that is g f x = f x
(assert (= (apply1 g (apply2 orBool True) True) (apply3 (apply2 orBool True) True)))

; Expand orBool True True = True, that is orBool True _ = True
(assert (= (apply3 (apply2 orBool True) True) True))
@VictorCMiraldo
Copy link
Contributor

This is not too different to how pirouette does things. It's just that we do it in separate passes. I do like how the expansion is a little more constrained. How do we know "when g or orBool need to be evaluated"?

@facundominguez
Copy link
Member Author

How do we know "when g or orBool need to be evaluated"?

That is a decision made by the algorithm driving the interaction with the SMT Solver. In the case of LH, PLE will unfold all the invocations of non-recursive functions, and all invocations of recursive functions whose guards have been decided (e.g. is the input list empty or not, is the input integer greater than 0, etc).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants