Comment revenez-vous d'une fonction à un point arbitraire?

12

Comment revenez-vous tôt d'une fonction avant qu'elle ne soit terminée? Par exemple:

(defun my-func () 
 "for example."
 (unless something (return nil))
 ; continue as usual...
 (+ 42 1))
ocodo
la source

Réponses:

19

Nous avons un certain nombre d'options disponibles.

Jeter

Vous pouvez catch/ throwpour quitter la fonction.

exemple:

(defun my-func ()
  "thrown error"
  (catch 'my-catch
    (when t
      (throw 'my-catch "always going to throw"))
    (+ 42 1)))

Bloquer

Vous pouvez également utiliser blocket return-from(même si vous en aurez besoin cl-macs)

exemple:

(require 'cl-macs)

(defun my-func ()
  "block / return-from"
  (block my-func
    (when t
      (return-from my-func))
    (+ 42 1)))

cl-defun

Nous avons aussi cl-defunqui a un implicite blockavec le même nom que la fonction, donc nous pouvons faire le blockstyle avec moins.

exemple:

(require 'cl-macs)

(cl-defun my-func ()
  "cl-defun implicit block"
  (when t
    (return-from my-func)) ; my-func is an implicit block.
  (+ 42 1)))

defun *

cl-defunest également disponible sous la forme d'un alias defun*défini comme suit cl.el:

(require 'cl)

(defun* my-func ()
  "defun* implicit block"
  (when t
    (return-from my-func)) ; my-func is an implicit block.
  (+ 42 1)))
ocodo
la source
4
Notez que si vous n'avez pas de préférence pour la syntaxe CL, catch/ throwest plus idiomatique dans elisp, car d'autres approches sont finalement implémentées en termes de catch / throw. Le manuel dit elisp: « La plupart des autres versions de Lisp, y compris Common Lisp, ont plusieurs façons de transférer le contrôle non séquentielle: return, return-fromet go., Par exemple Emacs Lisp a seulement throw. »
phils
5

En plus de ce que couvrait @EmacsFodder, il suffit de soulever une erreur.

Cela n'aidera pas si le code est appelé dans (dynamiquement, pas lexicalement) l'étendue des constructions de gestion des erreurs telles que ignore-errorsou condition-case, mais sinon c'est une bonne façon de quitter une fonction. C'est en fait ce qui se fait la plupart du temps.

(defun my-func () 
 "..."
 (unless something (error "Whoops!"))
 ; continue as usual...
 (+ 42 1))

Si vous voulez gérer l'erreur vous-même, vous pouvez mettre le code d'appel (par exemple, l'appel à quelque chose qui appelle finalement my-func) à l'intérieur de a condition-case. Encore une fois, c'est ce qui se fait la plupart du temps, au moins aussi souvent que d'utiliser catch+ throw. Tout dépend du comportement que vous souhaitez.

A dessiné
la source
Merci pour la réponse Drew, je suis d'accord que c'est une méthode assez courante. Cependant, le simple fait de faire un retour anticipé dans de nombreuses autres langues n'entraîne pas la complexité d'avoir à traiter ensuite une erreur. Lors de la recherche de l'ensemble de questions / réponses. Je cherchais spécifiquement des alternatives au style "erroring out" qui me semble toujours délicat. Je n'ai pas précisé cela explicitement dans le texte de la question.
ocodo
1
Tout dépend de ce que vous voulez faire. Si vous voulez mettre fin immédiatement, sans autre traitement / manipulation, le fait de générer une erreur est un bon moyen d'aller pour une sortie non locale, dans Emacs. Si vous voulez faire quelque chose au cours d' une sortie non locale, à savoir le manipuler d' une certaine manière, puis catch, unwind-protect, condition-caseetc. sont utiles. Il existe toute une section du manuel Elisp consacrée aux sorties non locales . (Et il n'y a rien de particulièrement maladroit chez aucun d'entre eux, OMI.)
Drew
"Feels" est bien sûr entièrement subjectif. Merci pour le manuel non local ref.
ocodo