Oldukça uzun süredir kullandığım bir süredir (kitabımın ikinci bir baskısı için yazdım, ancak çok kullanıyorum). Eğer argümanlar bazı değerlendirilmemiş kodları gösteriyorsa, o zaman test edilmemiş formunda (istenebilir ya da olmayabilir) belirli bir maddeyi temsil eden tek bir kod parçası istiyorsak test fonksiyonunun HoldAll
ya da HoldFirst
özniteliklerine sahip olması gerekir.
ClearAll[fastOr];
Attributes[fastOr] = {HoldRest};
fastOr[test_, {args___}] := fastOr[test, args];
fastOr[test_, args___] :=
TrueQ[Scan[
Function[arg, If[test[arg], Return[True]], HoldAll],
Hold[args]]];
Düzenleme: Ben sadece söz konusu bağlantılı sayfanın alt kısmında Daniel Reeves tarafından çözüm, buna çok benzer olduğunu gördük. En önemli fark şudur: hem kısa devreler hem de argümanları değerlendirilmemişken (aşağıya bakınız), Daniel sadece kısa devre yapan parçalara odaklanırken.
Kısa devre davranışı var. Bağımsız değişken formundaki argümanları korumak istediğimiz için HoldRest
özniteliğine ihtiyacımız var. Ayrıca, test
'a geçirilene kadar bağımsız olarak değerlendirilen argümanların her birini korumak için HoldAll
(veya HoldFirst
) özniteliğine de ihtiyacımız var. test
gövdesinde kullanılmadan önce değerlendirilip değerlendirilmeyeceği test
'un özelliklerine bağlıdır. Bir örnek olarak: burada
Clear[fullSquareQ];
fullSquareQ[x_Integer] := IntegerQ[Sqrt[x]];
In[13]:= Or @@ Map[fullSquareQ, Range[50000]] // Timing
Out[13]= {0.594, True}
In[14]:= fastOr[fullSquareQ, Evaluate[Range[10000]]] // Timing
Out[14]= {0., True}
biz bağımsız değişken olarak kod indükleyici yan etkiler (baskı) bazı parçaları geçen bir örnektir.
fastOr
Or
için maddelerinde olarak unevaluated kod genel parçalarını kabul beri
In[15]:= fastOr[# &, Print["*"]; False, Print["**"]; False,
Print["***"]; True, Print["****"]; False]
During evaluation of In[15]:= *
During evaluation of In[15]:= **
During evaluation of In[15]:= ***
Out[15]= True
Not
, etmelisin ki: sonuç zaten önceki maddede belirlenen beri geçen tartışmanın kodu çalıştırmak için şansı yok Başlangıç değerlerinde değerlendirileceklerini umursamadığınız takdirde
Evaluate
numaralı değerler listenizde sarın (yukarıdaki
Range
örneğinde olduğu gibi). Son olarak, nasıl kullanılabileceğini göstermek için
fastOr
için tutulan kodun programlı yapısını göstereceğim (dilerseniz tuttuğunuz ifadelerle çalışmayla ilgili küçük bir çarpışma kursu düşünün).bekletilen ifadelerle çalışırken aşağıdaki fonksiyonu çok kullanışlıdır:
joinHeld[a___Hold] := Hold @@ Replace[Hold[a], Hold[x___] :> Sequence[x], {1}];
Örnek:
İşte
In[26]:= joinHeld[Hold[Print[1]], Hold[Print[2], Print[3]], Hold[], Hold[Print[4]]]
Out[26]= Hold[Print[1], Print[2], Print[3], Print[4]]
programlı Baskı-s ile örnek kullanılmıştır düzenlenen argümanlar oluşturmak için kullanabilirsiniz nasıl yukarıda:
In[27]:=
held = joinHeld @@ MapThread[Hold[Print[#]; #2] &,
{NestList[# <> "*" &, "*", 3], {False, False, True, False}}]
Out[27]= Hold[Print["*"]; False, Print["**"]; False, Print["***"]; True, Print["****"]; False]
fastOr
onu geçmek için, başka kullanışlı deyim kullanır: hepimizin elde edene kadar Hold[args]
eklenecek (veya başa) fonksiyon argümanları ve ardından Apply
kullanmak (genel deyim Append[Hold[parts___],Unevaluated[newpart]]
benziyor bu yüzden biz sonuna ekliyorsunuz parça istemiyorsanız, genel olarak, dikkat/değerlendirmek için prepending, biz Unevaluated
sarın olmalıdır):
In[28]:= fastOr @@ Prepend[held, # &]
During evaluation of In[28]:= *
During evaluation of In[28]:= **
During evaluation of In[28]:= ***
Out[28]= True
Başvurduğunuz orijinal uygulama ile ilgili olarak, bir süre önce yaptığım yorumuma bakabilirsiniz. Sorun TakeWhile ve LengthWhile 8.0.0 paketlenmiş diziler için hatalar var, 8.0.1 kaynaklarda sabit - yani, 8.0.1'den başlayarak, benim ya da Michael'ın sürümünü kullanabilirsiniz.
HTH
Düzenleme:
Sadece anılan yayında, farklı bir sözdizimi istediğini fark
. Bu duruma, fastOr
numaralı kuralı kabul etmek çok zor olmasa da, burada bu söz dizimi için mevcut dil yapıları ile daha yakın bir ilişki içinde olan farklı bir uygulama var. Table
ve istisnaları kullanmanızı öneririm, çünkü yinelemeler Table
'da istediğiniz gibi aynı sözdizimini kabul eder. İşte burada: açıklama
ClearAll[AnyTrue, AllTrue];
SetAttributes[{AnyTrue, AllTrue}, HoldAll];
Module[{exany, exall},
AnyTrue[iter : {var_Symbol, lis_List}, expr_] :=
TrueQ[Catch[Table[If[TrueQ[expr], Throw[True, exany]], iter], exany]];
AllTrue[iter : {var_Symbol, lis_List}, expr_] :=
Catch[Table[If[! TrueQ[expr], Throw[False, exall]], iter], exall] =!= False;
];
birkaç kelime: Ben sadece bir kez tanımlamak gereken özel durum etiketleri beri üst düzeyde Modülü kullanmak, hem de tanım zamanında bunu yapabilir. Tablodan çıkmanın yolu istisnalardır. Çok zarif değil ve küçük bir performans artışı tetikliyor, ancak Table
tarafından yapılan yineleyici değişkenlerinizin otomatik dinamik lokalizasyonunu ve basitliğini satın alıyoruz. Bunu güvenli bir şekilde yapmak için, bir istisnayı benzersiz bir etiketle etiketlemeliyiz, bu nedenle yanlışlıkla başka bir istisna yakalamayız. Genel olarak çok yararlı bir hile olmak için kalıcı istisna etiketlerini oluşturmak için Modülü kullanarak buluyorum. Şimdi, bazı örnekler: - Bu Table
tarafından halledilir
In[40]:= i = 1
Out[40]= 1
In[41]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 3]
Out[41]= True
In[42]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 6]
Out[42]= False
In[43]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i > 3]
Out[43]= False
In[44]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i < 6]
Out[44]= True
In[45]:= AllTrue[{a, {1, 3, 5}}, AnyTrue[{b, {2, 4, 5}}, EvenQ[a + b]]]
Out[45]= True
In[46]:= AnyTrue[{a, {1, 3, 5}}, AllTrue[{b, {2, 4, 5}}, EvenQ[a + b]]]
Out[46]= False
Ben yineleyici değişkenlerinin olası küresel değerler önemi yok olduğunu göstermek için i
bir atama ile başladı. Son olarak, (başka yerde yorumladı gibi), AllTrue
için, orijinal imzaları dikkat ve AnyTrue
aşağıdaki çalışmıyor anlamında, biraz fazla kısıtlayıcı:
In[47]:= lst = Range[5];
AllTrue[{i, lst}, i > 3]
Out[48]= AllTrue[{i, lst}, i > 3]
(lst
bir listesini temsil gerçeği beri HoldAll
özniteliği nedeniyle desen eşleştirme zamanında bilinmez. Orada bu davranışı tutmak için iyi bir neden, bu nedenle sadece _List
kontrolleri kaldırabilirsiniz: AnyTrue[iter : {var_Symbol, lis_}, expr_]
ve benzer AllTrue
için ve kullanım durumları bu sınıf işlenecektir. performans üzerindeki etkileri hakkında emin, ama neredeyse emin değil
'LengthWhile [FromPackedArray @ lis', ... –
çalışır Evet, şu anda kullanıyorum, ancak bu tür bir görev için iyi bir genel stil daha ilgimi çekiyor –
Dokümanlardan ** ToPackedArray kullanmak Mathematica ** tarafından üretilen sonuçları değiştirmeyecek ... lier! lier! Pantolonlar ateş içinde! –