Zulip Chat Archive

Stream: general

Topic: Advent of Code?


Omri Schwarz (Dec 01 2023 at 05:29):

Is anyone trying to do Advent of Code in Lean this year?

Damiano Testa (Dec 01 2023 at 06:41):

I am.
(Not polished yet, but it should work!)

I plan to polish at least the first day or two, since I am planning to "Christmas" lecture on Lean as a programming language for my students.

Gareth Ma (Dec 01 2023 at 11:59):

Hi, I missed this thread. I’m also doing it in Lean (as well as a billion other languages, probably)

Gareth Ma (Dec 01 2023 at 12:06):

My terrible first attempt is at https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Advent.20of.20Code.202023 but it takes couple hours, I think

Omri Schwarz (Dec 01 2023 at 13:54):

First night of the advent and I missed how a misclick gave me the 1st day puzzle from 2015. ..

Gareth Ma (Dec 01 2023 at 14:06):

Also, the author has asked people not to publish their input data publicly: https://twitter.com/ericwastl/status/1465805354214830081

Omri Schwarz (Dec 01 2023 at 14:46):

And I am stuck because of what happens when digit words overlap, I think.

Gareth Ma (Dec 01 2023 at 14:51):

Yeah, a lot of people did

Arthur Adjedj (Dec 01 2023 at 17:16):

I will also be trying to do the Advent of Code here

Kyle Miller (Dec 01 2023 at 17:57):

I'm not sure how long I'll keep it up, but I have my solutions here

Wojciech Nawrocki (Dec 01 2023 at 18:06):

There is also an Advent of Proof!

Adam Topaz (Dec 01 2023 at 18:15):

Wojciech Nawrocki said:

There is also an Advent of Proof!

Is this supposed to just be a discord invite?

Wojciech Nawrocki (Dec 01 2023 at 18:19):

Adam Topaz said:

Wojciech Nawrocki said:

There is also an Advent of Proof!

Is this supposed to just be a discord invite?

There is a webpage, but it appears to ask for access to a Discord account to use as your submission account.

Gareth Ma (Dec 01 2023 at 18:47):

How hard is it? I will try tonight but I feel kind of nervous (???)

Gareth Ma (Dec 01 2023 at 19:59):

Okay it's not hard at all, at least D1

Frédéric Dupuis (Dec 01 2023 at 23:17):

I'm also doing it, at least for the first few days. Repository here.

Scott Morrison (Dec 01 2023 at 23:35):

Is anyone considering writing formal specs and proofs? :-)

I did day 1, and will probably do as many (in lean) as my kid does (in python). I didn't attempt to verify it, but looking at the code here are some basic facts that I would have wanted:

proof_wanted String.intercalate_splitOn {sep s : String} :
    sep.intercalate (s.splitOn sep) = s

proof_wanted List.insertionSort_sorted {l : List α} [DecidableRel r] :
    (l.insertionSort r).Sorted r

proof_wanted String.mem_findAllSubstr_iff {s : String} {p} :
    t  s.findAllSubstr p  t.str = s  t.toString = p

/-- `String.findAllSubstr` returns results in order. -/
proof_wanted String.findAllSubstr_sorted {s : String} {p} :
    (s.findAllSubstr p).map (Substring.startPos) |>.toList |>.Sorted (· < ·)

We really need to add the String instances for slim_check so we can sanity check statement like these; I bet at least one is wrong! :-)

Arthur Adjedj (Dec 01 2023 at 23:47):

The AOC might be a great opportunity to find missing functions/theorems currently missing in Lean. I found myself being limited in my options when writing my code. For example, manipulating Substring isn't so easy, since the functions aren't documented. Furthermore, I don't feel like the str[a:b] notation should give an Array as it does now, I feel like it would make sense for it to return a Substring, in the same way that arr[a:b] returns a Subarray for a given Array.

Frédéric Dupuis (Dec 02 2023 at 00:02):

Here's a problem that came up for me: how do we prove termination of a monadic parser, such as

partial def getFirstNum : Parsec Nat :=
  parseNumberForwards <|> (do let _  anyChar; getFirstNum)

where getFirstNum is another parser that tries to get a digit at the current position either as an actual digit or spelled out as a word. Here termination should be guaranteed by the fact that the string being parsed gets strictly shorter with every recursive call, but this is all hidden under monadic code.

Mario Carneiro (Dec 02 2023 at 00:08):

You can't, at least not written that way. One way you could do it is to have a Parsec.fix : (Parsec A -> Parsec A) -> Parsec A parser, which calls the passed function with a parser that acts like the one under construction except it fails if called from the same or lower string position

Mario Carneiro (Dec 02 2023 at 00:10):

Arthur Adjedj said:

The AOC might be a great opportunity to find missing functions/theorems currently missing in Lean.

I think this every year. Maybe what we should do is have a wiki page so that people can jot down their pain points or missing theorems as they come up. Or just post here on zulip

Frédéric Dupuis (Dec 02 2023 at 00:11):

Yeah, also I guess there's always the "fuel" trick:

def getFirstNum (fuel : Nat) : Parsec Nat :=
  parseNumberForwards <|> do
    if fuel = 0 then fail "end of string"
    else
      let _  anyChar
      getFirstNum (fuel-1)

Mario Carneiro (Dec 02 2023 at 00:11):

It's important to catch people in the moment though, because even a few hours later going back over the code you may already have forgotten what lemma you were missing and worked around

Mario Carneiro (Dec 02 2023 at 00:12):

@Frédéric Dupuis the downside of that version is that every recursive parser needs an if statement

Mario Carneiro (Dec 02 2023 at 00:13):

and you have to set the fuel correctly and prove that it is large enough etc

Frédéric Dupuis (Dec 02 2023 at 00:13):

Yeah, in this case it's not a big problem but it's definitely a downside.

Frédéric Dupuis (Dec 02 2023 at 00:22):

As for missing lemmas, would you welcome PRs to Std for functions like String.reverse or is this just going to get annoying?

Mario Carneiro (Dec 02 2023 at 00:23):

Yes certainly we want such theorems

Mario Carneiro (Dec 02 2023 at 00:23):

I think it's probably better to get the proof_wanted version of the theorems first though, the proofs can come later

Frédéric Dupuis (Dec 02 2023 at 00:25):

Right. (Though in this case it's just the function that reverses a string.)

Mario Carneiro (Dec 02 2023 at 00:26):

oh you mean the function itself, not the lemmas

Scott Morrison (Dec 02 2023 at 00:27):

We'd prefer lemmas over functions for now. :-)

Frédéric Dupuis (Dec 02 2023 at 00:27):

Alright, makes sense!

Mario Carneiro (Dec 02 2023 at 00:27):

rust std doesn't have a String::reverse so I'm a bit meh

Scott Morrison (Dec 02 2023 at 00:27):

I think PRs with new functions for Std are okay, but perhaps they could come with a fair bit of effort to include all the lemmas, at least as proof_wanted.

Scott Morrison (Dec 02 2023 at 00:29):

We would really like to get to the point where we know what is missing in terms of adding API, i.e. where we can post a graph of the number of proof_wanted statements and feel like getting it to zero will be a meaningful milestone.

Mario Carneiro (Dec 02 2023 at 00:29):

In fact I think we should push people to use proof_wanted more aggressively in those PRs, that way they can be focused on the API design rather than adding a bunch of work which may need to be discarded in response to definition changes

Frédéric Dupuis (Dec 02 2023 at 01:47):

So I guess this is what you had in mind, Mario?

def Parsec.fix (p : Parsec α  Parsec α) : Parsec α := fun it =>
  let p' : Parsec α := fun it' =>
    if h : it.s.endPos - it.i  it'.s.endPos - it'.i then
      .error it' "recursive call going backwards in the string"
    else
      have : it'.s.endPos - it'.i < it.s.endPos - it.i := by
        have h'' : ¬(it.s.endPos - it.i).byteIdx  (it'.s.endPos - it'.i).byteIdx := h
        rwa [Nat.not_le] at h''
      fix p it'
  p p' it
termination_by fix p it => it

def getFirstNum : Parsec Nat := fix fun p =>
  parseNumberForwards <|> do let _  anyChar; p

Frédéric Dupuis (Dec 02 2023 at 01:50):

Very nice, I expected this to be more painful.

Mario Carneiro (Dec 02 2023 at 01:50):

or more simply

def Parsec.fix (p : Parsec α  Parsec α) : Parsec α := fun it =>
  let p' : Parsec α := fun it' =>
    if it'.s.endPos - it'.i < it.s.endPos - it.i then
      fix p it'
    else
      .error it' "recursive call going backwards in the string"
  p p' it

Adomas Baliuka (Dec 02 2023 at 10:56):

What is parseNumberForwards? Loogle gives no hits.
(by the way, my AoC is here but I probably won't be using Parsec because I couldn't find a tutorial yet and it feels I'm doing it very wrong).

Adomas Baliuka (Dec 02 2023 at 10:57):

(deleted)

Frédéric Dupuis (Dec 02 2023 at 15:13):

@Adomas Baliuka You can find my full solutions here. This code is in Aoc2023/Day01.lean, and the functions I use there that are not in core or Std are in Aoc2023/Utils.lean.

Antanas Kalkauskas (Dec 02 2023 at 19:05):

I am also participating, here are my solutions. Hoping to go through the whole event.

Antanas Kalkauskas (Dec 02 2023 at 19:07):

Is anyone hosting a private Advent of Code leaderboard for lean4 solutions?

Yakov Pechersky (Dec 02 2023 at 22:44):

Mario Carneiro said:

or more simply

def Parsec.fix (p : Parsec α  Parsec α) : Parsec α := fun it =>
  let p' : Parsec α := fun it' =>
    if it'.s.endPos - it'.i < it.s.endPos - it.i then
      fix p it'
    else
      .error it' "recursive call going backwards in the string"
  p p' it

Can we reuse the parser propositions I developed for the lean3 parser here?

Mario Carneiro (Dec 02 2023 at 22:46):

quite possibly. I think they all have to be rewritten since the underlying types and operations have changed but the ideas should still work

Yakov Pechersky (Dec 02 2023 at 22:48):

Agree on the rewrite. There might be a need for special support in the termination checker for parsecs to look for a docs3#parser.prog

Liam O'Connor (Dec 03 2023 at 23:24):

Wojciech Nawrocki said:

There is also an Advent of Proof!

this is meant as a competition for beginners/intermediate lean users associated with the university of edinburgh's TypeSig and related student societies, not really for general admission. If this works well perhaps we will expand the scope next year.

Phil Nguyen (Dec 03 2023 at 23:53):

I am also using AoC to learn more about practical programming in Lean. Here are my solutions

For input processing, I'm either doing naive parsing using String.splitOn, or emacs's macros to massage the input. Are there tutorials/examples out there for using Lean's parser library? Thanks!

Frédéric Dupuis (Dec 04 2023 at 00:27):

I don't think there are any tutorials, but if you want a more extended example, I wrote a bibtex parser here. It's probably not great code though, this was my first attempt at using monadic parsers.

Adomas Baliuka (Dec 04 2023 at 00:42):

Can we make a "blessed" solution of AoC that shows best practices (while remaining concise so people can easily read all of it)? Which of the solutions referenced here so far (certainly not mine) might be candidates?

21eleven (Dec 04 2023 at 05:26):

Just joined this Zulip. I am using Advent of Code to learn Lean . Found this thread while searching for documentation on parsers :p

Mario Carneiro (Dec 04 2023 at 05:39):

@Adomas Baliuka Of the examples linked so far, I think Kyle's solutions are the most best-practice looking. It's a lot more work to write this kind of teaching material every day compared to just solving the problem though

Adomas Baliuka (Dec 04 2023 at 05:51):

I wonder, why are some definitions marked partial there? I removed it at two random examples and it seemed the keyword was not necessary. Why does one mark definitions partial when it's not needed to make Lean accept them?

Mario Carneiro (Dec 04 2023 at 06:01):

probably just copy pasta

Mario Carneiro (Dec 04 2023 at 06:02):

It's possibly a bit faster to compile if you don't have to do the termination proof? But for most functions this is barely noticeable

Kyle Miller (Dec 04 2023 at 18:53):

If you're talking about the partials in day 1 part 2, I just forgot to remove them. I started by writing a state machine to process characters one at a time, but then I realized there was docs#String.findAllSubstr (which uses a KMP matcher by the way) and went with that.

Kyle Miller (Dec 04 2023 at 18:57):

@Phil Nguyen I've been using Lean's Parsec library here and there. It's a bit anemic as a parser library, but it has just enough to be able to write what you need. Here is a parser for today's format. I put the ws whitespace parser probably in more places than I needed, which is harmless, but one gotcha is that because Parsec commits to a parse, I needed to write many (nat <* ws) instead of many (ws *> nat), since in the latter matching whitespace causes it to think there ought to be another nat.

I had to define the nat parser myself, and it's here.

Kyle Miller (Dec 04 2023 at 18:58):

I should have written a general sepBy parser, but instead in day 2 I wrote specialized versions. I'll probably factor it out when it's needed in a future day.

Adam Layne (Dec 05 2023 at 15:17):

My solutions are here. First time using Lean. Using it as an opportunity to get better at monads/applicatives.

Adam Layne (Dec 05 2023 at 15:18):

AoC23 seems pretty heavy on text parsing, so I should probably learn the parser library as well.

tristanC (Dec 05 2023 at 18:13):

Also using AoC to learn some Lean (coming from Haskell/Rust). I got to use Parsec for day 2. My solutions are here if that helps. It's a lot of fun, cheers :)

James Dabbs (Dec 05 2023 at 18:27):

Hey y'all :wave: Late to the party here, but I'm getting started as well. Similarly, just wrapped up my first non-trivial bit of parsing for day 2.

Notification Bot (Dec 05 2023 at 21:50):

Stuart Presnell has marked this topic as resolved.

Notification Bot (Dec 05 2023 at 21:50):

Stuart Presnell has marked this topic as unresolved.

Stuart Presnell (Dec 05 2023 at 21:51):

Sorry, misclicked the "mark as resolved" button

Phil Nguyen (Dec 07 2023 at 08:47):

Kind of silly, but is there a standard library function for sorting a list? I couldn't find it for day 7 so ended up implementing a basic one today. I tried autocompletion in emacs, and searching for {a : Type} -> [Ord a] -> List a -> List a on Loogle but couldn't find anything :upside_down:

Henrik Böving (Dec 07 2023 at 11:48):

I can offer you docs#Array.qsort but I think nobody bothered to implement list sorting yet

tristanC (Dec 07 2023 at 12:31):

For what it's worth, I propose this:

-- From https://codereview.stackexchange.com/questions/197868/bubble-sort-in-haskell
def swapTill [Min α] [Max α] (x : α) : List α -> List α
  | [] => [x]
  | y :: xs => min x y :: swapTill (max x y) xs
def List.bubbleSort [Min α] [Max α]: List α -> List α := List.foldr swapTill []

Frédéric Dupuis (Dec 07 2023 at 13:10):

docs#List.insertionSort

Kalle Kytölä (Dec 08 2023 at 14:30):

or docs#List.mergeSort.

ohhaimark (Dec 08 2023 at 23:43):

Doing AoC and find myself wanting to use Lean's builtin parser, perhaps naively. Is there an easy interface to it along the lines of parse : Parser -> String -> Option Syntax? I guess it is specialized to Lean enough to make this a chore and not a good idea.

Kyle Miller (Dec 09 2023 at 02:48):

You could use docs#Lean.Parser.runParserCategory for a parser category that you define, or here's some code for running a parser for a named syntax: https://github.com/nomeata/loogle/blob/master/Loogle.lean#L18

Steve Dunham (Dec 09 2023 at 04:21):

For sorting, I converted to an Array (.toArray.qsort). I suspect it's the fastest way, since it can mutate in place.

tristanC (Dec 09 2023 at 12:28):

Kyle Miller said:

You could use docs#Lean.Parser.runParserCategory for a parser category that you define

Thanks, that looks very useful. Though I can't find how to create the Lean.Environment, do we need to setup a CoreM for that? Is there an example that demonstrates using runParserCategory from the main IO Unit?

Alok Singh (S1'17) (Dec 10 2023 at 07:20):

would anyone like to pair on advent? i live in the bay area and i just started aoc. i'm on part 1b (writing a parser combinator to handle it, or figuring out Lean.Data.Parsec). i'm familiar with functional programming.

Shubham Kumar 🦀 (he/him) (Dec 10 2023 at 15:54):

Alok Singh (S1'17) said:

would anyone like to pair on advent? i live in the bay area and i just started aoc. i'm on part 1b (writing a parser combinator to handle it, or figuring out Lean.Data.Parsec). i'm familiar with functional programming.

https://github.com/leanprover-community/lean4-samples/blob/main/CSVParser/README.md

I was also thinking the same and I saw this one is archived but maybe can help in understanding Parsec.

Shubham Kumar 🦀 (he/him) (Dec 10 2023 at 16:02):

Steve Dunham said:

For sorting, I converted to an Array (.toArray.qsort). I suspect it's the fastest way, since it can mutate in place.

I did the same didn't know how to add Mathlib to the project, maybe need to have a look at FPIL

Mac Malone (Dec 10 2023 at 20:49):

ohhaimark said:

Doing AoC and find myself wanting to use Lean's builtin parser, perhaps naively. Is there an easy interface to it along the lines of parse : Parser -> String -> Option Syntax? I guess it is specialized to Lean enough to make this a chore and not a good idea.

tristanC said:

Kyle Miller said:

You could use docs#Lean.Parser.runParserCategory for a parser category that you define

Thanks, that looks very useful. Though I can't find how to create the Lean.Environment, do we need to setup a CoreM for that? Is there an example that demonstrates using runParserCategory from the main IO Unit?

The Partax library provides an interface for converting Lean syntax / parsers into simpler functions that can be easily run without a full Lean.Enviroment. (Sorry for the shameless self-plug!)

Kyle Miller (Dec 10 2023 at 20:53):

That also avoids what Loogle needs to do, which is to embed Lean (using supportInterpreter := true in the lakefile) and then set up CoreM by importing modules: https://github.com/nomeata/loogle/blob/master/Loogle.lean#L142

If you're not attached to doing runParserCategory from the command line, then you can use #eval, which can run CoreM using the current environment at that point.

Kyle Miller (Dec 11 2023 at 00:57):

Today's part 2 was mathematically interesting, though yesterday task was a classic.

Frédéric Dupuis (Dec 11 2023 at 02:24):

I just went with the first thing that popped into my head, namely:

Kyle Miller (Dec 11 2023 at 03:34):

@Frédéric Dupuis I like that idea to manipulate the data. It makes it conceptually clear what's being calculated. Mine takes an arbitrary choice (a direction) which is a bit inelegant.

Frédéric Dupuis (Dec 11 2023 at 04:04):

I also spent an embarrassing amount of time playing with this sort of pattern for verification, which looked quite promising:

structure PropWrapper (p : Prop) where
  pf : p

def checkThat {α : Type _} (x : α) (p : α  Prop) [ a, Decidable (p a)] :
    Option (PropWrapper (p x)) :=
  if h : p x then some h
  else none

def Array.checkThatAll {α : Type _} (xs : Array α) (p : α  Prop) [ a, Decidable (p a)] :
    Option (PropWrapper ( i, (h : i < xs.size)  p xs[i])) :=
  match h : xs.all p with
  | false => none
  | true =>
      have hmain :  (i : Fin xs.size), p xs[i] := by
        have htmp := (xs.all_eq_true _).mp h
        simpa [decide_eq_true_iff] using htmp
      some fun i hi => hmain i, hi⟩⟩

def toyExample (input : FilePath) : IO Unit := do
  let data := ( IO.FS.lines input).map String.toCharArray
  let some hdata := checkThat data fun as => 0 < as.size | panic! "no input"
  -- here I have `hdata : 0 < as.size` in context
  let firstrow := data[0]   -- which lets me access the first element without using `data[0]!`
  let some hdata' :=
    data.checkThatAll fun as => as.size = data[0].size | panic! "Rows not all the same size!"
  -- here I have `hdata' : ∀ i < data.size, data[i].size = data[0].size` in context

Frédéric Dupuis (Dec 11 2023 at 04:05):

It seems like a clean way to get proofs of facts we want asserted, and that we can then use later in the code to e.g. check array bounds.

Kyle Miller (Dec 11 2023 at 05:14):

docs#PLift is the core Lean structure for PropWrapper btw. That pattern seems to be similar to this one, which came up when someone was asking about this recently.

Frédéric Dupuis (Dec 11 2023 at 05:33):

Thanks! I figured something like this had to exist...

Damiano Testa (Dec 11 2023 at 07:23):

spoiler

ohhaimark (Dec 11 2023 at 17:33):

Getting a stack overflow but no stack trace. I'm running a built executable through lake exe, so I'm not sure if running it interpreted would get a stack trace. Is there a debug flag I can set for executable targets or an easy way to run a lake exe on the interpreter with stack traces?

Getting used to strict evaluation and having foldr be a no no.
EDIT: tried buildType := BuildType.debug, still no stack trace

Henrik Böving (Dec 11 2023 at 17:46):

@ohhaimark does your binary coredump? If so you can easily get a stacktrace from that using any reasonably good C debugger.

ohhaimark (Dec 11 2023 at 17:47):

Henrik Böving said:

ohhaimark does your binary coredump? If so you can easily get a stacktrace from that using any reasonably good C debugger.

Ah, running it through lean exe didn't print that it core dumped, but running the binary directly did.

Now to remember the systemd incantation to find it.

Henrik Böving (Dec 11 2023 at 17:55):

coredumpctl debug if you have a somewhat recent distro @ohhaimark

ohhaimark (Dec 11 2023 at 17:55):

Ah, it seems the foldl in the parser library I'm using (https://github.com/fgdorais/lean4-parser) isn't tail recursive.

Kyle Miller (Dec 11 2023 at 18:00):

@Damiano Testa

ohhaimark (Dec 11 2023 at 18:00):

@[specialize f]
private partial def foldAux (f : γ  β  γ) (y : γ) (p : ParserT ε σ α m β) : ParserT ε σ α m γ :=
  let rec rest (y : γ) : ParserT ε σ α m γ :=
    try
      let x  withBacktracking p
      rest (f y x)
    catch _ => return y
  rest y

Or maybe it's specialized to my f that is screwing things, but that doesn't explain the repeated foldAux in the backtrace.

ohhaimark (Dec 11 2023 at 18:03):

I guess the try-catch could muddy the waters, haven't thought too deeply about how that translates. Or just the parser monad in general. I use the SimpleParserT with StateT ... ExceptT ... Id, so maybe in SimpleParser it is tail recursive.

ohhaimark (Dec 11 2023 at 18:10):

Using parser combinators at the stage I'm on (Day 3) is overkill anyway, but now I stubbornly want to get this to work. This is why I never get anything done.

Damiano Testa (Dec 11 2023 at 18:20):

@Kyle Miller

spoiler

Kyle Miller (Dec 11 2023 at 18:24):

@Damiano Testa

Damiano Testa (Dec 11 2023 at 18:26):

@Kyle Miller

spoiler

Mario Carneiro (Dec 12 2023 at 06:25):

@ohhaimark Your foldAux is not tail-recursive, it calls rest inside a tryCatch which means it builds up a stack of tryCatches

ohhaimark (Dec 12 2023 at 08:19):

Mario Carneiro said:

ohhaimark Your foldAux is not tail-recursive, it calls rest inside a tryCatch which means it builds up a stack of tryCatches

It's the library's. I've filed an issue https://github.com/fgdorais/lean4-parser/issues/5.

From the issue:
In the process of trying to come up with a minimal example for, I caused an internal panic instead :sob:.

import Parser
import Parser.Char

open Parser Parser.Char Std

abbrev P := SimpleParser Substring Char

def test : IO Unit := do
  let x := Parser.run (Parser.foldl (fun _ _ => ()) (pure ()) (pure ()) : P Unit) ""
  match x with
  | .ok _ res => pure res
  | .error err => IO.println err
def main : IO Unit := test

stdout/stderr

INTERNAL PANIC: unreachable code has been reached

Where do I report upstream?

Mario Carneiro (Dec 12 2023 at 08:27):

looks like it's already fixed upstream

Mario Carneiro (Dec 12 2023 at 08:27):

Actually can you make a lean4-parser-free MWE for the INTERNAL PANIC issue?

ohhaimark (Dec 12 2023 at 08:40):

Mario Carneiro said:

looks like it's already fixed upstream

I tried, but I don't know enough about the cause to understand how to repro without it.

Mario Carneiro (Dec 12 2023 at 08:44):

I mean can you just inline what you need and remove things as long as the problem persists

Mario Carneiro (Dec 12 2023 at 08:44):

You presumably only need the Parser type, Parser.run and Parser.foldl to make this (mis)compile

Mario Carneiro (Dec 12 2023 at 08:45):

you should pull up the Output panel so that you can see when the panic occurs, since only the first panic in a session gets a popup

Alok Singh (S1'17) (Dec 12 2023 at 19:22):

I'm livestreaming day 2 at https://www.youtube.com/watch?v=IgeXFbOG_Nc

Steve Dunham (Dec 13 2023 at 05:01):

For day 10 part 2,

Steve Dunham (Dec 13 2023 at 05:07):

To show totality in day12, I needed to tell lean that List.drop returned something the same or smaller than its argument. I ended up coming up with this, but I'm somewhat new to proofs in Lean 4. Is there a better way to do this:

theorem drop_le (r : Nat) (cs : List Char) :  sizeOf (cs.drop r) <= sizeOf cs := by
  revert cs
  induction r
  intro cs
  apply Nat.le_of_eq; rfl
  intro cs
  cases cs
  apply Nat.le_of_eq; rfl
  rename_i n ih head tail
  apply Nat.le_trans (ih tail)
  simp [Nat.le_add_left]

Full code, but spoilers, at https://github.com/dunhamsteve/aoc2023/blob/main/day12/day12.lean

Steve Dunham (Dec 13 2023 at 22:31):

Working from phone:
IMG_4478.PNG

Phil Nguyen (Dec 18 2023 at 06:10):

Is there a library function for parsing a hex string to a Nat? Thanks! (I figure it's straightforward but just wonder if the library already has it)

Phil Nguyen (Dec 20 2023 at 02:17):

Day 19 was pretty fun. What I did was writing a monadic interpreter for the language, then by swapping out the monad, we obtain the standard semantics for q1, and symbolic execution for q2. I found out Lean doesn't really have something like ListT in Haskell (probably because it's not practical in an eager language?). Also I think I need to learn more about Parsec to write less verbose parsers...


Last updated: Dec 20 2023 at 11:08 UTC