Karmaşık kısım döngüdür. Şununla başlayalım. Bir döngü genellikle, yinelemeyi tek bir fonksiyonla ifade ederek işlevsel stile dönüştürülür. Bir yineleme döngü değişkeninin bir dönüşümüdür.
İşte genel bir döngünün işlevsel bir uygulaması:
loop : v -> (v -> v) -> (v -> Bool) -> v
loop init iter cond_to_cont =
if cond_to_cont init
then loop (iter init) iter cond
else init
(Döngü değişkeninin başlangıç değeri, tek bir yinelemeyi ifade eden fonksiyon [döngü değişkeninde]) alır (döngüye devam etme koşulu).
Örnekte, aynı zamanda sonlanan bir dizi üzerinde bir döngü kullanılıyor. Zorunlu dilin içindeki bu yetenek dilin kendisine aittir. İşlevsel programlamada, bu yetenek genellikle kütüphane seviyesinde uygulanır. İşte olası bir uygulama
module Array (foldlc) where
foldlc : v -> (v -> e -> v) -> (v -> Bool) -> Array e -> v
foldlc init iter cond_to_cont arr =
loop
(init, 0)
(λ (val, next_pos) -> (iter val (at next_pos arr), next_pos + 1))
(λ (val, next_pos) -> and (cond_to_cont val) (next_pos < size arr))
İçinde :
Dışarıda görülebilen loop değişkenini ve bu fonksiyonun gizlediği dizideki pozisyonu içeren bir ((val, next_pos)) çifti kullanırım.
Yineleme işlevi genel döngüde olduğundan biraz daha karmaşıktır, bu sürüm dizinin geçerli öğesini kullanmayı mümkün kılar. [ Curried formunda]
Bu fonksiyonlara genellikle "katlama" adı verilir.
Dizideki elementlerin birikiminin soldan bağlantılı bir şekilde yapıldığını belirtmek için isminde bir "l" koyuyorum; zorunlu programlama dillerinin alışkanlıklarını taklit etmek için diziyi düşükten yükseğe dizine yineleme.
Bu kıvrım sürümünün, döngünün ne zaman durdurulup durdurulmayacağını ve ne zaman olacağını kontrol eden bir koşul aldığını belirtmek için bir "c" harfi koydum.
Elbette, bu tür faydalı fonksiyonların, kullanılan işlevsel programlama dili ile birlikte verilen temel kütüphanede hazır bulunması muhtemeldir. Onları gösteri için buraya yazdım.
Artık zorunlu durumda dilde olan tüm araçlara sahip olduğumuza göre, örneğinizin belirli işlevlerini yerine getirebiliriz.
Döngünüzdeki değişken bir çifttir ('cevap', devam edip etmeyeceğini kodlayan bir boolean).
iter : (Int, Bool) -> Int -> (Int, Bool)
iter (answer, cont) collection_element =
let new_answer = answer + collection_element
in case new_answer of
10 -> (new_answer, false)
150 -> (new_answer + 100, true)
_ -> (new_answer, true)
Yeni bir "değişken" "new_answer" kullandığımı unutmayın. Bunun nedeni, işlevsel programlamada önceden başlatılmış bir "değişken" in değerini değiştiremememdir. Performans hakkında endişelenmiyorum, derleyici daha etkili olduğunu düşünüyorsa, 'new_answer' için 'cevap' hafızasını tekrar tekrar kullanabilir.
Bunu daha önce geliştirilen loop fonksiyonumuza dahil etmek:
doSomeCalc :: Array Int -> Int
doSomeCalc arr = fst (Array.foldlc (0, true) iter snd arr)
Burada "Array" işlevi, foldlc işlevini veren modül adıdır.
"fist", "second", pair parametresinin birinci, ikinci bileşenini döndüren işlevleri belirtir
fst : (x, y) -> x
snd : (x, y) -> y
Bu durumda "puansız" stil doSomeCalc uygulamasının okunabilirliğini arttırır:
doSomeCalc = Array.foldlc (0, true) iter snd >>> fst
(>>>) işlev bileşimidir: (>>>) : (a -> b) -> (b -> c) -> (a -> c)
Yukarıdakiyle aynıdır, sadece "arr" parametresi tanımlayıcı denklemin her iki tarafından bırakılmıştır.
Son bir şey: vaka kontrolü (array == null). Daha iyi tasarlanmış programlama dillerinde, ancak bazı temel disipline sahip kötü tasarlanmış dillerde bile, var olmayanları ifade etmek için isteğe bağlı bir tür kullanılır . Bunun, sorunun nihayetinde olduğu fonksiyonel programlama ile ilgisi yok, bu yüzden onunla ilgilenmiyorum.
break
vereturn answer
birreturn
iç döngü ile değiştirilebileceğini unutmayın . FP size örneğin bkz devamlılık kullanarak bu erken dönmek uygulamak en.wikipedia.org/wiki/Continuation