[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#13126: 24.3.50; (WISH) Document pcase in Info manual
From: |
Jambunathan K |
Subject: |
bug#13126: 24.3.50; (WISH) Document pcase in Info manual |
Date: |
Thu, 13 Dec 2012 20:31:57 +0530 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) |
Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> Thanks. `pcase' seemed a good replacement for `case'.
>
> While it's not a plug-in replacement, it provides a superset of the
> features of case, yes.
pcase also reminds me of CL's case. Btw, you know in what version of
Emacs did pcase made it's appearance.
>> 1. pcase-let, pcase-let*, pcase-dolist (maybe)
>
> pcase-dolist shouldn't be documented (yet?). Maybe pcase-let and
> pcase-let* should be there, indeed.
>
pcase-let reminds me of `destructuring-bind'.
Here is a real-life example of pcase-let in action from midnight.el.
Good for instructive purposes.
(defun midnight-next ()
"Return the number of seconds till the next midnight."
(pcase-let ((`(,sec ,min ,hrs) (decode-time)))
(- (* 24 60 60) (* 60 60 hrs) (* 60 min) sec)))
>> 2. It took some effort to understand that there is a U-PATTERN and a
>> UPATTERN. We don't read out `*-*', do we?
>> ,----
>> | There are two kinds of patterns involved in `pcase', called
>> | _U-patterns_ and _Q-patterns_. The UPATTERN mentioned above are
>> | U-patterns and can take the following forms:
>> `----
Provide a BNF and document TERMINALS before NON-TERMINALS. (Currently it
seems other way round).
Docstring for pcase has more info (pred FUNCTION) apropos the arguments
passed to it. Possibly there are other things...
> What do you suggest instead?
Here is my recommendation.
May be replace the example snippets with a /simple/ and /cohesive/
example. I found Snippet 2 "too abstract" and leaves a lot to the
imagination of the reader.
I just hacked a working REPL based on pcase. See below. We can include
these after
`repl' will act as a good replacement for Snippet 1. `repl-eval' will
act as a good replacement for Snippet 2.
M-x repl RET for a reader to toy with.
,---- Snippet 1
| (pcase (get-return-code x)
| (`success (message "Done!"))
| (`would-block (message "Sorry, can't do it now"))
| (`read-only (message "The shmliblick is read-only"))
| (`access-denied (message "You do not have the needed rights"))
| (code (message "Unknown return code %S" code)))
`----
,---- Snippet 2
| (defun evaluate (exp env)
| (pcase exp
| (`(add ,x ,y) (+ (evaluate x env) (evaluate y env)))
| (`(call ,fun ,arg) (funcall (evaluate fun) (evaluate arg env)))
| (`(fn ,arg ,body) (lambda (val)
| (evaluate body (cons (cons arg val) env))))
| ((pred numberp) exp)
| ((pred symbolp) (cdr (assq exp env)))
| (_ (error "Unknown expression %S" exp))))
`----
(let ((repl-dictionary '()))
(repl-eval '((x = "happy")
(y = "HACKING")
(n = 2013)
(z = (upcase-initials x + space +
(downcase y) + tab + 2013)))))
(defvar repl-dictionary '()
"Symbol table for `repl'.")
(defun repl-eval (exp)
(pcase exp
;; In-built constants.
(`space " ")
(`tab "\t")
;; Add operator. Concatenate.
(`(,x + . ,y) (concat (repl-eval x ) (repl-eval y)))
;; Assignment operator. Update dictionary.
(`(,x = . ,body) (let* ((value (repl-eval body))
(entry (assoc x repl-dictionary)))
(if (not entry)
;; Add variable & value.
(push (cons x value) repl-dictionary)
;; Update value.
(setcdr entry value))
value))
;; Function. Assume it takes a string as it's only arg. Call it.
(`(,(and (pred functionp) f) . ,x) (funcall f (repl-eval x)))
;; Last of body forms. Return it's value.
(`(,x . nil)
(repl-eval x))
;; Body forms. Evaluate in sequence. Return value of last of
;; the forms.
(`(,x . ,y) (repl-eval x) (repl-eval y))
;; String, just return it.
((pred stringp) exp)
;; Number, cast it to string.
((pred numberp) (number-to-string exp))
;; Symbol, lookup it's value in dictionary.
((pred symbolp) (or (cdr (assoc exp repl-dictionary))
(error "Variable `%s' not bound" exp)))
(_ (error "Unknown expression %S" exp))))
(defun repl ()
"Simple REPL for string operations.
Expression syntax:
In-built Constants : space
: tab
Assignment : x = \"hello\"
: y = \"world\"
Casting : n = 2012
Concatenation : x + space + y + space + n
Unary functions : (upcase-initials x)
Commands:
exit => Quit
clear => Unbind all variables
examine => Examine currently defined variables."
(interactive)
(let ((repl-dictionary '())
(prompt "STRING-REPL> ")
(result nil))
(while (pcase (read-from-minibuffer prompt)
(input
(pcase input
("exit" (setq result nil))
("clear" (setq repl-dictionary '()
result "[CLEARED]"))
("examine" (setq result (format "%S" repl-dictionary)))
(_ (let ((exp (read (format "(%s)" input))))
(setq result (condition-case err
(repl-eval exp)
(error (format "%s" err)))))))
(when result
(minibuffer-message
(concat prompt input
(propertize "\t" 'display
(list 'space :align-to 40))
(propertize result 'face 'highlight))))))
(setq result nil))))