[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug#66562] [PATCH v3] gnu: emacs-haskell-snippets: Use correct director
From: |
Liliana Marie Prikler |
Subject: |
[bug#66562] [PATCH v3] gnu: emacs-haskell-snippets: Use correct directory for snippets. |
Date: |
Tue, 17 Oct 2023 19:29:20 +0200 |
User-agent: |
Evolution 3.46.4 |
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
bug#66562: [PATCH v3] gnu: emacs-haskell-snippets: Use correct directory for snippets., Liliana Marie Prikler, 2023/10/23