Zulip Chat Archive

Stream: lean4

Topic: Disconnected syntax


Damiano Testa (Aug 13 2023 at 15:08):

Dear All,

is it possible to throw an error at a disconnected syntax? Here is an example of what I would like to achieve:

import Lean.Elab.Tactic.Basic

open Lean

elab "twoErrors" e1:term "~" e2:term : tactic => do
  throwErrorAt e1 "Can there be a red squiggle also under {e2}"
  throwErrorAt e2 "I would like to also underline e2"

example : True := by
  twoErrors 0 ~ 1  -- Can there be a red squiggle also under 1

Thanks!

Damiano Testa (Aug 13 2023 at 15:24):

I see that it is possible:

#eval let x : List Nat := [0, 1, _, 4, _] -- both underscores are underlined, and nothing else

but I still do not know how to achieve it myself! :smile:

Mario Carneiro (Aug 13 2023 at 17:09):

don't use throwErrorAt, that has control flow effects. Use logError if you just want to add a squiggle

Mario Carneiro (Aug 13 2023 at 17:10):

note that I have said something along the lines of "logError considered harmful" in the past though, because it interacts in surprising ways with control flow combinators like try / repeat

Mario Carneiro (Aug 13 2023 at 17:14):

import Lean
open Lean

elab "foo" : tactic => do
  logError "you can't foo right now"

elab "bar" : tactic => do
  throwError "you can't bar right now"

-- one nice thing about `logError`
-- is that you can keep giving errors after the tactic
example : True := by
  foo -- error
  bar -- error
  foo

-- one not nice thing about `logError`
-- is that you can't suppress the error, at least with normal combinators
example : True := by
  try bar
  try foo -- error
  trivial

Damiano Testa (Aug 13 2023 at 18:12):

Mario, thank you very much! I like this and I am planning to then log the errors and then throw an error, since I do not want to continue!

Damiano Testa (Aug 13 2023 at 18:13):

Basically, my use-case is that I want to throw an error when the user passes a list of terms, some of which are not suitable, and underline the unsuitable ones, but definitely throw an error after underlining!

Damiano Testa (Aug 14 2023 at 06:32):

Here is a sample of something similar to what I had in mind:

import Lean

open Lean Elab TSyntax in
elab nm:"evens?" nats:(colGt num),* : tactic => do
  let odds := nats.getElems.filter (getNat · % 2 = 1)
  guard (odds.size = 0) *> logInfoAt nm "All even!" <|>
    odds.mapM (logErrorAt · .nil) *>
    throwErrorAt nm m!"The underlined numbers {odds} are odd!"

example : True := by
  evens? 0, 1, 2, 3, 4, 5, 10001  -- The underlined numbers [1, 3, 5, 10001] are odd!

example : True := by
  evens? 0, 2, 4, 1000    --  All even!
  trivial

Damiano Testa (Aug 14 2023 at 09:14):

Here is the "guess the sequence" version of the above:

import Lean

--  SPOILER ALERT: do not look at the implementation!  Go to the last line
open Lean in
elab nm:"guess_the_next_number!" nats:(colGt num),* : command => do
  let mut (data, incorrects) := (#[], #[])
  let mut con := 0
  for elt in nats.getElems do
    if elt.getNat != 2 ^ con then
      logErrorAt elt .nil
      if con  3 then data := data.push elt else incorrects := incorrects.push elt
    con := con + 1
  let init := if data.size  3 then m!"The sequence begins with 1, 2, 4, 8." else .nil
  match incorrects.size, nats.getElems.size with
    | 0, n => logInfoAt nm
                (if n  3 then init ++ " Make a guess!"
                 else if n = 4 then "Make a guess!"
                 else "🎉 Guess accomplished!  Keep guessing, if you want")
    | _, _ => incorrects.mapM (logErrorAt · .nil) *>
              throwErrorAt nm m!"The underlined numbers {data ++ incorrects} are wrong!"

-- avoid looking at the implementation above!

guess_the_next_number!

Last updated: Dec 20 2023 at 11:08 UTC