Convert hex to bin in Guile Scheme

Unfortunatly, Guile doesn't provide a method to convert hex to bin (When I'm writing, the current version is 2.0.11). People have to write their own one.

But fortunatly, writing code in Scheme is kind of enjoy. Every time I've done my program in Scheme, a new idea will strike my head to refactor it. Then you can't stop to continue to program.

Well, sometimes, we just want a quick way to do our job. But in Scheme, you may become a lib/framework writer unexpectedly. Maybe it's the worst point of Scheme. And one may enjoy wasting such time...hey I'm sorry Boss...

Here's my version, you may take it for free, or donate some fixes/suggestions/comments. ;-)

(use-modules (rnrs)) ; we need bytevectors in rnrs module

(define (%numstr->bin str final base)
  (define len (string-length str))
  (let lp((i 0) (ret '()))
     ((= i len) (final (reverse! ret)))
     (else (lp (+ i 2) (cons (string->number (substring str i (+ i 2)) base) ret))))))
;; NOTE: substring in Guile happens to be copy-on-write, so it would be efficient

(define (hex->bin str)
  (%numstr->bin str u8-list->bytevector 16))

(define (hex->list str)
  (%numstr->bin str identity 16))

(define (hex->ascii str)
  (%numstr->bin str (lambda (x) (utf8->string (u8-list->bytevector x))) 16))

;; (hex->bin "4a4b4c")
;; => #vu8(74 75 76)

;; (hex->list "4a4b4c")
;; => (74 75 76)

;; (hex->ascii "4a4b4c")
;; => "JKL"

In the beginning, I just need hex->bin, but finally, I wrote a high order function for a tiny hex lib.

Response to comments:

Suggestions from @Raymond:

1) get rid of the `final' argument of %numstr->bin.

(%numstr->bin str final base) isn't any shorter or faster than (final (%numstr->bin str base)); in the latter case it's easier to understand what's happening and there aren't as many positional parameters to remember.

Answer:Yes, you're right. I agree a callback in final position could be optimized out and put it outside.

2) rename %numstr->bin to %numstr->u8-list.

If you eliminate the `final' parameter as suggested, then %numstr->bin always returns the same type, and you can use a more descriptive name.

Answer:Yes, it's a related optimize. ;-)