Nikita Karetnikov <nik...@karetnikov.org> skribis: > But it doesn't work. These lines rise an error: > > + (cons (gnu-package-descriptor > + (inherit (first state)) > + ((eval (match-field str) > + (interaction-environment)) str)) > > (There may be other problems. For instance, it should remove fields' > names from 'str' before creating a record.) > > What do you think about the 'eval' idea? It's used to avoid unnecessary > repetition.
“Eval is evil”, as lispers love to say. It should never be used, unless there’s a very good reason to do so. In my unfinished binary substitute where a similar situation arises, I’ve done this: (define (fields->alist port) "Read recutils-style record from PORT and return them as a list of key/value pairs." (define field-rx (make-regexp "^([[:graph:]]+): (.*)$")) (let loop ((line (read-line port)) (result '())) (cond ((eof-object? line) (reverse result)) ((regexp-exec field-rx line) => (lambda (match) (cons (match:substring match 1) (match:substring match 2)))) (else (error "unmatched line" line))))) (define (alist->record alist make keys) "Apply MAKE to the values associated with KEYS in ALIST." (let ((args (map (cut assoc-ref alist <>) keys))) (apply make args))) And then, it is used like this: (alist->record properties (cut %make-cache url <...>) '("StoreDir" "WantMassQuery")) To summarize, the input port containing a list of key/value pairs (like yours) is first read by ‘fields->alist’, which returns a list of key/value pairs. Then ‘alist->record’ converts that alist into a record. In this example, it calls ‘%make-cache’ in a way equivalent to: (%make-cache (assoc-ref properties "StoreDir") (assoc-ref properties "WantMassQuery")) Here ‘%make-cache’ is the ‘normal’ SRFI-9 constructor, which is called ‘make-gnu-package-descriptor’ in your code. Let me know if you need more details. Thanks, Ludo’.