Is there a way to format keys/values like raise-arguments-error

36 views
Skip to first unread message

David Storrs

unread,
Sep 8, 2021, 9:41:56 AM9/8/21
to Racket Users
raise-arguments-errors produces neatly stacked key/value pairs with whitespace arranged such that values line up even when keys are of different lengths.  Is there an easy way to get that for something that is not an error?  I've been through both The Printer and the raise-arguments-error sections in the Reference and can't find anything.

For example:

(doit "x" 1 "foo" 2 "super" 3)

Returns the string "x     1\nfoo   2\super 3"




kamist...@gmail.com

unread,
Sep 9, 2021, 4:11:56 PM9/9/21
to Racket Users
I am not really aware of a function that does this you could try digging into the implementation of raise-arguments-error,
usually I roll my own implementation depending on what I really want to output.
racket/format and its ~a, ~v, etc. have a lot of useful optional keyword arguments like #:align #:pad-string #:width etc.

This isn't totally what you want, but maybe it has something that is useful to you.
This or similar code is what I have used sometimes:

#lang racket

(define current-prefix-length (make-parameter 0))
(define (prefixln #:prefix [prefix ""]
                  #:align  [align 'left]
                  . message)
  (displayln (apply ~a (list* (~a prefix #:width (current-prefix-length) #:align align)
                              message))))

(define-syntax-rule (with-indent body ...)
  (parameterize ([current-prefix-length (+ (current-prefix-length) 2)])
    body ...))

(define (example-func1)
  (prefixln "start of example func1")
  (with-indent
    (example-func2))
  (prefixln "end of example func1"))

(define (example-func2)
  (prefixln "start of example func2")
  (prefixln "end of example func2"))


(module+ main

  (displayln "Hello checkout these values:")
  (define example-values
    (hash 'foo 123
          'this-is-a-long-key "some value"
          'blabla #f
          "cake" "is a lie"))

  ;; ugly oneliner to calculate prefix width
  (current-prefix-length (+ 2 (foldl max 0 (map (compose1 string-length ~a) (hash-keys example-values)))))

  (for ([(k v) (in-hash example-values)]) ;; probably sorting or assoc list would make sense too...
    (prefixln #:prefix (~a k ": ") #:align 'right
              v))

  (current-prefix-length 0)
  (displayln "")
  (displayln "indentation through multiple nested calls:")
  (with-indent
    (example-func1)))

If you use a current-prefix-string parameter instead you can create other interesting things like lines indented with indentation level indicators, etc.:
indent0
| indent1
| | indent2
| indent1
indent0

But I am getting too off-topic...

Simon

Laurent

unread,
Sep 9, 2021, 5:26:59 PM9/9/21
to David Storrs, Racket Users
Maybe take a look at the text-table package.

--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CAE8gKod_s8EhQPW9uG7P02%3D8Kmpqf2Uw%3DKLORWD%3DwmFrxnGkWA%40mail.gmail.com.

David Storrs

unread,
Sep 10, 2021, 1:01:39 PM9/10/21
to kamist...@gmail.com, Racket Users

Wow, thank you Simon.  That was above and beyond.

I should have thought of ~a to start with.  With your pointers I came up with a less flexible solution that is sufficient to the current issue:


#lang racket/base
(require racket/format
         racket/string)

(define my-keys   '("bacon" "eggs" "pancakes"))
(define my-vals   '("turkey" "whites" "blueberry"))

(define (make-str keys vals)
  (define width (apply max (map string-length keys)))
  (string-join
   (for/list ([k keys]
              [v vals])
     (format "\t~a" (~a (~a k #:width width) v #:separator "\t")))
   "\n"))

(displayln (make-str my-keys my-vals))



--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.

David Storrs

unread,
Sep 10, 2021, 1:04:04 PM9/10/21
to Laurent, Racket Users
Thank you, Laurent.  That's a cool package; I think it would work well to generate tables suitable for org-mode spreadsheets.  I could even pull data from a sqlite DB, giving me power and portability without needing an internet connection or a full heavyweight spreadsheet app.

kamist...@gmail.com

unread,
Sep 10, 2021, 1:33:40 PM9/10/21
to Racket Users
I like the apply max instead of foldl, quite a bit easier.

Instead of `(format "\t~a" (~a (~a k #:width width) v #:separator "\t"))` I prefer one of these:
(~a "\t" (~a k #:width width) "\t" v)
(~a #:separator "\t" "" (~a k #:width width) v)

David Storrs

unread,
Sep 10, 2021, 2:10:48 PM9/10/21
to kamist...@gmail.com, Racket Users
Fiiiiine.  If you want to be all efficient and readable, go right ahead.

Thanks, applied.  :>


--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages