Zulip Chat Archive
Stream: lean4
Topic: Exercise 2.4 Functional Programming in Lean 4
Austin Anderson (Jun 26 2024 at 20:22):
Does anyone have a solution to the "--help" exercise in section 2.4? Among other things, I tried the code below where everything except lines 4-7 is from the textbook. One problem I'm getting is IO Unit and IO UInt32 are mismatched types and I don't know how to put a message like "you want help" in type IO UInt32. Thanks!
def process (exitCode : UInt32) (args : List String) : IO UInt32 := do
match args with
| [] => pure exitCode
| "--help" :: args =>
let stdout ← s!"You want help!"
dump stdout
process exitCode args
| "-" :: args =>
let stdin ← IO.getStdin
dump stdin
process exitCode args
| filename :: args =>
let stream ← fileStream ⟨filename⟩
match stream with
| none =>
process 1 args
| some stream =>
dump stream
process exitCode args
Henrik Böving (Jun 26 2024 at 20:24):
Please use #backticks for your code. Note that there is no need to put the string into the IO
monad, you can just use a normal let binding: let stdout := "You want help!"
Austin Anderson (Jun 26 2024 at 22:27):
Thank you. So below is the whole thing, all but 3 lines copied from Functional Programming in Lean section 2.4. And it gives an error when I type
lake build
in terminal. The error is below that.
def bufsize : USize := 20*1024
partial def dump (stream : IO.FS.Stream) : IO Unit := do
let buf ← stream.read bufsize
if buf.isEmpty then
pure ()
else
let stdout ← IO.getStdout
stdout.write buf
dump stream
def fileStream (filename : System.FilePath) : IO (Option IO.FS.Stream) := do
let fileExists ← filename.pathExists
if not fileExists then
let stderr ← IO.getStderr
stderr.putStrLn s!"File not fizzound: {filename}"
pure none
else
let handle ← IO.FS.Handle.mk filename IO.FS.Mode.read
pure (some (IO.FS.Stream.ofHandle handle))
def process (exitCode : UInt32) (args : List String) : IO UInt32 := do
match args with
| [] => pure exitCode
| "--help" :: args =>
let stdout := "You want help!"
dump stdout
process exitCode args
| "-" :: args =>
let stdin ← IO.getStdin
dump stdin
process exitCode args
| filename :: args =>
let stream ← fileStream ⟨filename⟩
match stream with
| none =>
process 1 args
| some stream =>
dump stream
process exitCode args
def main (args : List String) : IO UInt32 :=
match args with
| [] => process 0 ["-"]
| _ => process 0 args
```
```
```quote
error: ././././Main.lean:25:18: type mismatch
toString "You want help!"
has type
String : Type
but is expected to have type
IO ?m.1151 : Type
error: Lean exited with code 1
Some builds logged failures:
- Main
error: build failed
```
Kim Morrison (Jun 27 2024 at 03:38):
I'm confused. There is no toString "You want help!"
in your code. When I open your code in the sandbox I see:
application type mismatch
dump stdout
argument
stdout
has type
String : Type
but is expected to have type
IO.FS.Stream : Type
instead.
Austin Anderson (Jun 27 2024 at 20:35):
Thanks for the reply. I had a line that said
but per Henrik's comment I changed it to
let stdout := "You want help!"
I have tried multiple things, but really just wonder what David Thrane Christiansen had in mind for the exercise he wrote. Perhaps something not fully covered in the book section is required.
Austin Anderson (Jun 27 2024 at 20:36):
sorry retry. I had
let stdout ← s!"You want help!"
Paul Rowe (Jun 27 2024 at 20:55):
I think the idea of the exercise is to make it a slightly more realistic program by making it act the way many command line programs do. For example, if you type code --help
on the command line, the effect is to print a bunch of information about how to use the code
command. It's a simple way to document the intended usage and list of available command line options.
So when you type <prog_name> --help
this should have the effect of printing this documentation to stdout
and returning a UInt32 to indicate success (usually 0).
Austin Anderson (Jul 01 2024 at 20:50):
Thank you. I agree. But I think a simple message like "you want help!" is a start, and since I cannot even get that to work, I'm at a loss.
Kim Morrison (Jul 01 2024 at 23:30):
Could you post the code you have so far, with #backticks and error messages matching the code?
David Thrane Christiansen (Jul 02 2024 at 11:17):
I don't want to just post a solution, but here's a hint.
It looks to me like you're using stdout
as the name of the text that is to be sent to standard output. But the intention in the chapter is that stdout
refers to the Lean representation of the stdout
file descriptor/output stream - that is, it's a place to which streams can be sent.
The dump
function expects to take an input stream as its argument, and it then loops until the stream runs out of data, sending its contents to standard output. Presumably, this is not something that should be done when users ask for help, because those users aren't looking to actually concatenate any streams.
Here's a program that isn't feline
, but that does have a help message. See if you can figure out how it's doing what it does, and then adapt it to the exercise's other argument handling:
def main (args : List String) : IO UInt32 := do
match args with
| [] =>
IO.println "OK"
return 0
| ["--help"] =>
IO.println "Usage information:"
IO.println " --help Show this usage information"
IO.println ""
IO.println "Run with no arguments to complete successfully."
return 1
| arg :: _ =>
IO.eprintln s!"Didn't understand argument \"{arg}\""
return 2
François G. Dorais (Jul 02 2024 at 23:10):
Another hint might be <https://github.com/leanprover/lean4-cli>
Austin Anderson (Jul 03 2024 at 04:19):
Thank you very much! My original attempt now works. I know its cheekily incomplete, but I learned a lot and understand at least one way it could be completed. When I type .lake/build/bin/feline --help test1.txt test2.txt
I get
You want help!
Time to find a warm spot
and curl up.
Thanks very much for writing the book! I'm a math guy and have only used Lean to formalize math so far, but I'm trying to understand LeanDojo and LLMStep for which I find your book extremely helpful. My hero!
My code is below.
partial def dump (stream : IO.FS.Stream) : IO Unit := do
let buf ← stream.read bufsize
if buf.isEmpty then
pure ()
else
let stdout ← IO.getStdout
stdout.write buf
dump stream
def fileStream (filename : System.FilePath) : IO (Option IO.FS.Stream) := do
let fileExists ← filename.pathExists
if not fileExists then
let stderr ← IO.getStderr
stderr.putStrLn s!"File not fizzound: {filename}"
pure none
else
let handle ← IO.FS.Handle.mk filename IO.FS.Mode.read
pure (some (IO.FS.Stream.ofHandle handle))
def process (exitCode : UInt32) (args : List String) : IO UInt32 := do
match args with
| [] => pure exitCode
| "--help" :: args =>
IO.println "You want help!"
process exitCode args
| "-" :: args =>
let stdin ← IO.getStdin
dump stdin
process exitCode args
| filename :: args =>
let stream ← fileStream ⟨filename⟩
match stream with
| none =>
process 1 args
| some stream =>
dump stream
process exitCode args
def main (args : List String) : IO UInt32 :=
match args with
| [] => process 0 ["-"]
| _ => process 0 args
Austin Anderson (Jul 03 2024 at 04:21):
(deleted)
Last updated: May 02 2025 at 03:31 UTC