Zulip Chat Archive

Stream: lean4

Topic: Large inductive enum timeouts


Pedro Oliveira (Jun 08 2023 at 00:20):

Whilst creating some libclang bindings I've come across a problem: I want to port a large enum from libclang (https://clang.llvm.org/doxygen/group__CINDEX.html#gaaccc432245b4cd9f2d470913f9ef0013) and I thought that an inductive type would fit best.

1   inductive CursorKind where
2   | UnexposedDecl
3   | StructDecl
4   | UnionDecl
...
285 | ConceptDecl
286 | FirstExtraDecl
287 | LastExtraDecl
288 | OverloadCandidate

This compiles fine, but when I create a simple fromNat function for CursorKind:

def fromNat : Nat  CursorKind
| 1 => UnexposedDecl
| 2 => StructDecl
| 3 => UnionDecl
...
| 604 => ConceptDecl
| 700 => OverloadCandidate
| _ => OverloadCandidate

The compiler seems to struggle with this definition:

CursorKind.lean:293:0: error: (deterministic) timeout at 'whnf', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)
CursorKind.lean:293:0: error: (deterministic) timeout at 'isDefEq', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)
CursorKind.lean:293:0: error: (deterministic) timeout at 'isDefEq', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)
CursorKind.lean:292:4: error: (deterministic) timeout at 'whnf', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)

I don't feel like setting the maximum heartbeats will help. What's the alternative to an inductive type here?

Mario Carneiro (Jun 08 2023 at 00:56):

it sounds like the issue is not the inductive type but rather the Nat pattern match

Mario Carneiro (Jun 08 2023 at 00:56):

does it work if you replace all the match arms by ()?

Pedro Oliveira (Jun 08 2023 at 01:00):

I think that it's the Nat pattern match too

Pedro Oliveira (Jun 08 2023 at 01:00):

When I replace the match arms, since they're all just redundant alternatives I can't actually compile the program

Mario Carneiro (Jun 08 2023 at 01:01):

I mean the RHS of the arms

Pedro Oliveira (Jun 08 2023 at 01:02):

Same error message as before:

CursorKind.lean:293:0: error: (deterministic) timeout at 'whnf', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)
CursorKind.lean:293:0: error: (deterministic) timeout at 'isDefEq', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)
CursorKind.lean:293:0: error: (deterministic) timeout at 'isDefEq', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)
CursorKind.lean:292:4: error: (deterministic) timeout at 'whnf', maximum number of heartbeats (200000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)```

Pedro Oliveira (Jun 08 2023 at 01:02):

Seems to be the Nat patterns

Mario Carneiro (Jun 08 2023 at 01:03):

Probably increasing the timeout will actually work, although it's not a great solution

Mario Carneiro (Jun 08 2023 at 01:03):

You could put all the options in an array and index into it

Pedro Oliveira (Jun 08 2023 at 01:04):

Yeah, I personally dislike increasing the timeout though. Another solution is just to use raw numbers instead of naturals, or to generate lots of constants

Mario Carneiro (Jun 08 2023 at 01:04):

Oh I see, it's just a bunch of constants

Mario Carneiro (Jun 08 2023 at 01:04):

that will probably work better

Mario Carneiro (Jun 08 2023 at 01:05):

you can use a macro to automate that kind of thing

Pedro Oliveira (Jun 08 2023 at 01:05):

Ill try this out

Pedro Oliveira (Jun 08 2023 at 01:05):

Although I can't see why lean struggles to pattern match the Nats

Pedro Oliveira (Jun 08 2023 at 02:46):

I ended up just writing a macro for enumerations:

syntax enumPair := ident "=" term
syntax "enum" ident "where" enumPair,+ : command

macro_rules
| `(enum $name:ident where $[$a = $b],*) => do
  let defs  (a.zip b).foldlM (init :=  `(namespace $name)) fun ns (a, b) =>
    `($ns
      def $a := $b)
  `($defs:command
    end $name)

enum CursorKind where
  CXCursor_UnexposedDecl = 1,
  CXCursor_StructDecl = 2,
  CXCursor_UnionDecl = 3,
  CXCursor_ClassDecl = 4,
  CXCursor_EnumDecl = 5,
  CXCursor_FieldDecl = 6,
  CXCursor_EnumConstantDecl = 7,
  CXCursor_FunctionDecl = 8,
  CXCursor_VarDecl = 9,
  CXCursor_ParmDecl = 10,
  CXCursor_ObjCInterfaceDecl = 11,
  ...
  CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
  CXCursor_LastExtraDecl = CXCursor_ConceptDecl,
  CXCursor_OverloadCandidate = 700

Last updated: Dec 20 2023 at 11:08 UTC