2011-09-19 11 views
8

Haskell ile uğraşıyorum ve bir şeyleri tekrarlamak için özyinelemeyi kullanma fikri.Bu parçacık nasıl Haskell'e çevrilir?

Örneğin

, nasıl

// this might seem silly but I need to do it 
list1 = empty list 
list2 = list of numbers 
for i from 0 to N // N being a positive integer 
    for each number in list2 
     if number == i, add to list1 

'fonksiyonel paradigma' haline çevirir misin? Herhangi bir rehberlik takdir edilecektir.

cevap

9

gidiyor adımı:

list2 = list of numbers 

Biz list2 hala numaraların sadece bir listedir, verilen bir olarak alacağız.

for i from 0 to N // N being a positive integer 

Haskell bunu yapmanın doğru yolu listesiyle genellikle. Tembellik, değerlerin sadece kullanıldığında hesaplanacağı anlamına gelir, böylece 0'dan N'ye kadar bir listeyi geçmek, burada sahip olduğunuz döngü ile aynı şeydir. Yani, sadece [0..n] hile yapacak; Sadece onunla ne yapacağımızı anlamaya ihtiyacımız var. Verilen

for each number in list2 

"için her bir" biz burada list2 bütününü çapraz gerekir olmadığını anlıyoruz; Bununla ne yapıyoruz, henüz bilmiyoruz.

if number == i, add to list1 

Biz giderken biz, list1 inşa ediyoruz bu yüzden ideal olarak biz bu ifadenin nihai sonucu olmak istiyorum. Bu aynı zamanda her tekrar adımında, sonucun "şimdiye kadar" olan list1 olmasını istiyoruz demektir. Bunu yapmak için, her adımın sonucunu geçtikçe geçirdiğimizden emin olmalıyız.

Yani, bunun ete aşağı alma:

filter fonksiyonu bazı yüklem uyan bir listedeki tüm unsurları bulur

; Neyin peşinde olduğumuzu bulmak için filter (== i) list2'u kullanacağız, sonra bunu bir önceki adımın sonucuna ekleriz. Bu nedenle, her adım şu şekilde görünecektir: Bu, iç döngüyü ele alır. Geriye doğru adım attığımızda, her bir adımda iletilen list1 değerinin [0..n] listesinden i numaralı her bir değer için bunu çalıştırmamız gerekir.tekrarlama olduğunda, hem filter ve foldl bizim için yapıyoruz

list2 :: (Num a) => [a] 
list2 = -- whatever goes here... 

step :: (Num a) => [a] -> a -> [a] 
step list1 i = list1 ++ filter (== i) list2 

list1 :: (Num a) => a -> [a] 
list1 n = foldl step [] [0..n] 

Eğer merak ediyorsanız: Bu fonksiyonlar içindir ve bu durumda step biz sol kat için tam ihtiyacımız olan şey kat tam olarak ne . Genel bir kural olarak, bunu sizin için yapacak daha üst düzey işlevler olduğunda doğrudan özyineleme önlemek genellikle daha iyidir.


burada algoritma çeşitli şekillerde saçma, dedi ki, ama buna yardımcı olacağını daha gerçek sorudan rahatsız olur gibi görünüyordu çünkü içine almak istemiyordu.

+0

Neden açık bir birleştirme adımı üzerinde katlanmak yerine 'concatMap' kullanılmıyor? – bdonlan

+2

Bu durumda, liste kavrayışını kullanabilirsiniz: [number | i <- [1..N], sayı <-list2, i == number], yani sahte kodunuzun doğrudan çevirisi. – ysdx

+0

Harika bir cevap için teşekkürler. Gönderdiğim snippet’in tuhaf olduğunu anlıyorum. Yaptığım bir yarıçap sıralama egzersizinin bir parçası. –

10

Üzgünüm, ama yardım ancak daha iyi bir algoritma kullanamazsınız ...

let goodNumber n = (0 <= n && n < N) 
let list1 = sort (filter goodNumber list2) 

Düzenleme: OP bir uygulamaya çalışıyordu beri bu overkill biraz vardır Gez ilk sırada algo sıralama. Adım

0
let list1 = sort [a | a<-list2, a>=0, a<=N] 

a<-list2 tarafından alınıp list2 her sayı a>=0, a<=N onay aldı sayı şartlar yerine getirildiği takdirde, bir list2 tüm unsurları böylece kontrol edildikten sonra yeni bir listeye konur ve TÜM bu koşulları yerine getirmesi halinde Yeni bir listeye koydu, bu üzerinde bir sıralama yapıyoruz Liste lere atanmış liste1