[isabelle-dev] Let and tuple case expressions

Dmitriy Traytel traytel at in.tum.de
Thu Aug 27 11:03:23 CEST 2015

Hi Florian,

On 27.08.2015 10:03, Florian Haftmann wrote:
> Hi Dmitriy,
>> In short, I have come to the conclusion that
>>    let (a, b) = p in t
>>    case p of (a, b) => t
>> at the moment being logically distinct, should be one and the same.  In
>> other words, I suggest that any case expression on tuples should be
>> printed using »let« rather than »case«.  The constant »Let« would turn
>> into a degenerate case combinator with no actual pattern match.
> I tried to change this in the expectation that tuning the syntax rules
> for Let would be sufficient, but found out that's not the case: if case
> is to be interwoven with let, the syntax machinery for let must act on
> the same syntactic layer to behave consistently (the usual observation
> when dealing with syntax).
> Hence, to go forward here, it is inevitable to extend the case syntax
> code itself, roughly as follows:
> a) Map »case x of y ⇒ f y« to »Let x f« and vice versa.
> b) Map singleton case clauses to let clauses and vice versa.
> c) Collapse/expand consecutive let clauses (let x = y in let z = w in …
> <--> let x = y; z = w in …)
> Since I suppose you know that code best, how feasible does this agenda
> look for you?  I guess a) has to be implemented in Isabelle/ML anyway,
> but maybe then b) and c) are simple enough to be achieved using »syntax«
> productions.
I am slightly confused by "and vice versa". Clearly you want the mapping 
to go in one direction. There are two questions: (1) what is the logical 
representation (2) what is printed.

If I understand you correctly you want the answer for both to be Let 
expressions (for case combinators of single-constructor (co)datatypes). 
Then I would say, the way to go is to implement a syntax phase for 
translating the affected case combinators into Let expressions and 
install it *after* the case syntax translation phase. Something along 
the following lines (generalized beyond the product type).

ML ‹
fun Let_of_case ctxt ts =
     fun substT T =
         val ((U1, (U2, U3)), (U4, U5)) = T |> dest_funT |>> (dest_funT 
##> dest_funT) ||> dest_funT;
         U4 --> (HOLogic.mk_prodT (U1, U2) --> U3) --> U5

     fun subst (Const (@{const_name case_prod}, T) $ rhs $ t) =
       Const (@{const_name Let}, substT T) $ (subst t) $ 
(HOLogic.mk_split (subst rhs))
       | subst (t $ u) = subst t $ subst u
       | subst t = t
     map subst ts

val _ = Context.>> (Syntax_Phases.term_check 2 "case → Let" Let_of_case)

This, however, does not work with (a), since today "case x of y ⇒ f y" 
is translated to "f x". But the question is anyway whether this is not 
what you want.

In contrast, if you would like to have the case combinators as the 
logical representation, the translation of Let into case probably should 
happen before the case syntax translation phase (and would be more 
complicated). Printing then would work roughly as in the code above 
(replace "check 2" with "uncheck 0").

In any case I would prefer not to extend the case syntax translation 
itself, since it is quite complicated already.

Hope that helps,

More information about the isabelle-dev mailing list