Subject: [bug#66562] [PATCH v3] gnu: emacs-haskell-snippets: Use correct directory for snippets.

From: Liliana Marie Prikler <[email-masked]>
Date: Tue, 17 Oct 2023 19:29:20 +0200

Hi, Rostislav

Am Dienstag, dem 17.10.2023 um 18:49 +0200 schrieb Rostislav Svoboda:
> […]
> > Plus you're requiring let* instead of let.
> 
> Having both variants is a language deficiency, in my opinion. Only
> let should exist, functioning as let* does. This should extend to
> lambda*, define*, etc.
Only let should exist, functioning as let does.  let* is sugar on top.
(Not serious about this, there are reasons to have let*, but there are
also reasons it's not the default behaviour.)

> > Btw. don't
> >   ((compose
> >     (lambda (src dst) (mkdir-p src) (copy-recursively dst src))
> >     (lambda (dir store) (values dir (string-append store "/" dir)))
> >    "snippets/haskell-mode" (elpa-directory (assoc-ref outputs
> > "out")))
> > to avoid gratuitous repetition.
> 
> On the one hand, we face gratuitous repetition; on the other, a
> snippet like this better expresses compositional transformation
> between inputs and outputs, which I find to be a way more important
> that avoiding gratuitous repetition (pun intended). And as a side
> effect it also simplifies debugging:
> 
> ((compose
>   ;; (lambda (a b) (format #t "[DBG] 3. a: ~a; b: ~a\n" a b) (values
> a b))
>   (lambda (src dst) (mkdir-p src) (copy-recursively src dst))
>   ;; (lambda (a b) (format #t "[DBG] 2. a: ~a; b: ~a\n" a b) (values
> a b))
>   (lambda (dir store) (values dir (string-append store "/" dir)))
>   ;; (lambda (a b) (format #t "[DBG] 1. a: ~a; b: ~a\n" a b) (values
> a b))
>   )
>  "snippets/haskell-mode" (elpa-directory (assoc-ref outputs "out")))
If you need to warp your head around through three debug statements,
I'm not convinced you're improving the overall code all that much.

> And if you insist, the gratuitous repetition could, in theory, be
> avoided:
> 
> ((compose
>   copy-recursively
>   (juxt mkdir-p (partial string-append (elpa-directory (assoc-ref
> outputs "out")) "/")))
>  "snippets/haskell-mode")
> 
> Only if partial and juxt would exist... and here you go ;-)
> 
> (define (partial fun . args)
>   "Partial function application."
>   (lambda x (apply fun (append args x))))
> 
> (define (juxt . fns)
>   "Naive implementation. Inspired by Clojure's juxt.
> ((juxt a b c) x) => (list (a x) (b x) (c x))"
>   (lambda args
>     (map (lambda (fn) (apply fn args)) fns)))
> 
> Here yet another pattern appears, the map-reduce. Also the juxt
> function just screams for "let's call the mkdir-p and (partial
> string-append ...) in parallel".
You can do all that, but it does go against the KISS principle :)

> > Btw. don't (compose ...)
> 
> Quite the contrary, I think we should do more of (compose ...),
> however functional composition is hard-to-impossible if e.g.:
> 
> - essential higher order functions like juxt and partial are not
> available.
We have partial.  We call it cut.  It's part of SRFI-26.
It even simplifies the definition of juxt: 
(lambda args (map (cut apply <> args) fns))
Anyhow, we quite often don't use it because we'd have to add it to
#:modules and the benefit over raw lambdas is often negligible.

> - mkdir-p and copy-recursively from the (guix build utils) aren't
> monadic and mkdir-p returns #t instead of a path-string and
> copy-recursively returns:
> 
>   scheme@(guile-user)> ,use (guix build utils)
>   scheme@(guile-user)> (copy-recursively "/tmp/f1.txt" "/tmp/f2.txt")
>   `/tmp/foo.txt' -> `/tmp/fox.txt'
> 
>   eeeh... what exactly is the return value of copy-recursively? Hmm.
It returns *unspecified*.  Yes, most of this stuff is indeed not
monadic.  Scheme is not purely functional, so side effects are allowed
:)

> - copy-recursively, although naturally a reducer (i.e. a member of
> the fold-family, think of 'a list of things goes into a container')
> is not implemented as such. Hmm, disappointing... although a <...>-
> fold is used in its implementation. Double hmm.
There is a cost to constructing the return value of a fold.  I
personally can do without creating lists that no one will end up
inspecting anyway.

> - in general, the built-in compose function can't be called with zero
> arguments. For that purpose I cobbled myself:
> 
> (define (comp . fns)
>   "Like `compose'. Can be called with zero arguments. I.e. (thunk?
> comp) => #t
> Works also for functions returning and accepting multiple values."
>   (lambda args
>     (if (null? fns)
>         (apply values args)
>         (let [(proc (car fns)) (rest (cdr fns))]
>           (if (null? rest)
>               (apply proc args)
>               (let ((g (apply comp rest)))
>                 (call-with-values (lambda () (apply g args))
> proc)))))))
I'd argue that compose without procedures is quite meaningless, but
maybe I'm thinking too hard.

> And finally, in the (guix build utils) there's the install-file which
> works with single files. What about adding its recursive version:
> 
> (define* (install-recursively source destination
>                               #:key
>                               (log (current-output-port))
>                               (follow-symlinks? #f)
>                               (copy-file copy-file)
>                               keep-mtime? keep-permissions?)
>   "Recursive version of install-file."
>   (mkdir-p destination)
>   (copy-recursively source
>                     (string-append destination "/" (basename
> destination))
>                     #:log log
>                     #:follow-symlinks? follow-symlinks?
>                     #:copy-file copy-file
>                     #:keep-mtime? keep-mtime?
>                     #:keep-permissions? keep-permissions?))
There'd be no point in having copy-recursively then.  For a more
complete build system that already takes care of all that without
having you fiddling with juxt, partial, etc., just take copy-build-
system.  Not that it's needed here, mind you.

Cheers