2010-11-15 2 views
3

Je voudrais une fonction AnyTrue[expr,{i,{i1,i2,...}}] qui vérifie si expr est True pour l'une des i1,i2... Il devrait être comme si AnyTrue a été Table suivie [email protected]@%, avec la différence qu'il ne évalue expr jusqu'à trouver le premier True.fonction personnalisée avec une évaluation non standard (se comporte comme le tableau)

La mise en court-circuit est optionnelle, ce que j'aimerais vraiment savoir, c'est la bonne façon d'émuler la séquence d'évaluation non-standard de Table.

Mise à jour 11/14

Voici une solution en raison de Michael, vous pouvez l'utiliser à la chaîne "pour tous" et "il existe" contrôles

SetAttributes[AllTrue, HoldAll]; 
SetAttributes[AnyTrue, HoldAll]; 
AllTrue[{var_Symbol, lis_List}, expr_] := 
    LengthWhile[lis, 
    TrueQ[ReleaseHold[Hold[expr] /. HoldPattern[var] -> #]] &] == 
    Length[lis]; 
AnyTrue[{var_Symbol, lis_List}, expr_] := 
    LengthWhile[lis, 
    Not[TrueQ[ReleaseHold[Hold[expr] /. HoldPattern[var] -> #]]] &] < 
    Length[lis]; 
AllTrue[{a, {1, 3, 5}}, AnyTrue[{b, {2, 4, 5}}, EvenQ[a + b]]] 
AnyTrue[{a, {1, 3, 5}}, AllTrue[{b, {2, 4, 5}}, EvenQ[a + b]]] 

Répondre

5

Comment cela?

SetAttributes[AnyTrue, HoldAll]; 

AnyTrue[expr_, {var_Symbol, lis_List}] := 
    LengthWhile[lis, 
    Not[TrueQ[ReleaseHold[Hold[expr] /. HoldPattern[var] -> #]]] & 
    ] < Length[lis] 

Comprend un court-circuit via LengthWhile et conserve tout lieu si nécessaire pour que les choses fonctionnent comme prévu avec var a une valeur en dehors de la fonction:

In[161]:= x = 777; 

In[162]:= AnyTrue[Print["x=", x]; x == 3, {x, {1, 2, 3, 4, 5}}] 
During evaluation of In[162]:= x=1 
During evaluation of In[162]:= x=2  
During evaluation of In[162]:= x=3 
Out[162]= True 

Le haut-Or est court-circuit aussi, pour ce que ça vaut. (Mais je réalise construire les termes non évalués avec par exemple Table est une douleur):

In[173]:= Or[Print[1];True, Print[2];False] 
During evaluation of In[173]:= 1 
Out[173]= True 
+0

yup, travaille perfe ct –

+1

venant en retard, je voudrais juste souligner que les détails excessifs dans les modèles d'arguments ne vont pas souvent bien avec les attributs Hold. Par exemple, l'appel suivant échoue: AnyTrue [i <10, {i, Range [5]}], alors qu'en principe il ne devrait pas (le motif ne correspond pas car au moment de l'appariement de pattern il ne connait pas cette plage [ 5] est Liste). Cette signature légèrement plus générale va supprimer ce problème: AnyTrue [expr_, {var_Symbol, lis_}]. En outre, AnyTrue ne fonctionne pas dans M8 sur les listes emballées - il semble y avoir un bug dans LengthWhile: LengthWhile [Range [5],! TrueQ [# <10] &] donne 5, je vais le signaler. –

+0

Oui, bon point Leonid. Il vaudrait mieux avoir un modèle plus général et valider l'argument après l'avoir évalué. 'HoldAll' au lieu de' HoldFirst' est nécessaire car nous voulons conserver 'var' en plus de' expr', sinon il n'y aurait pas de problème avec le motif le plus exigeant. –

4

Cela ne correspond pas à vos spécifications, mais j'utilise souvent les fonctions d'utilité suivantes, qui sont semblables à ce que vous avez à l'esprit (ils utilisent des fonctions pures au lieu d'expressions avec une variable spécifiée) et aussi faire un court-circuit:

some[f_, l_List] := True ===    (* Whether f applied to some  *) 
    Scan[If[f[#], Return[True]]&, l];   (* element of list is True.  *) 

every[f_, l_List] := Null ===    (* Similarly, And @@ f/@l   *) 
    Scan[If[!f[#], Return[False]]&, l];  (* (but with lazy evaluation). *) 

Par exemple, l'exemple de Michael Pilat deviendrait ceci:

In[1]:= some[(Print["x=", #]; # == 3)&, {1, 2, 3, 4, 5}] 

    During evaluation of In[1]:= x=1 
    During evaluation of In[1]:= x=2  
    During evaluation of In[1]:= x=3 
Out[1]= True 
+1

Astuce utile.Notez que l'utilisation de "If" au lieu de "TrueQ" requiert un peu plus de soin avec la syntaxe, ie 'every [False, {a, {1, 3, 5}}] donne" True " –

+0

Vous m'avez inquiété au début mais Je ne pense pas qu'il y ait un bug ici. Notez que le premier argument doit être une fonction. 'every [False &, {1,3,5}]' fonctionne comme prévu. – dreeves

+0

A droite, pas de bug, juste une différence sémantique subtile, puisque c'est "Vrai" si f évalue à "autre chose que Faux" pour chaque élément de la liste –