Bu, öğrenmek istediğiniz anlamdaki programlama dilinde daha akıcı olmak için güzel bir alıştırmadır, ancak yalnızca hafifçe canlandırın. Bu, nesnelerle çalışmayı, kapakları kullanmayı veya taklit etmeyi ve tip sistemini genişletmeyi içerir.
Göreviniz tembel listeleri yönetmek için kod yazmak, ardından Fibonacci sayıları oluşturmak için bu algoritmayı uygulamak için kullanmaktır:
Kod örnekleri Haskell'de
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
in take 40 fibs
Sonuç:
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986]
Tembel liste uygulamanızın aşağıdaki kurallara uyması gerekir:
- Bir Liste düğümü üç şeyden biridir:
- Nil - Boş liste.
[]
- Eksileri - Kalan öğelerin bir listesiyle eşleştirilmiş tek bir öğe:
1 : [2,3,4,5]
(:
Haskell'deki eksileri operatörüdür) - Thunk - Gerektiğinde bir Liste düğümü üreten ertelenmiş bir hesaplama.
- Nil - Boş liste.
- Aşağıdaki işlemleri desteklemektedir:
- nil - Boş bir liste oluşturun.
- cons - Bir cons hücresi oluşturun.
- thunk - Argüman almayan ve bir Nil veya Eksileri döndüren bir işlev verilen bir Thunk oluşturun.
- force - List düğümü verildiğinde:
- Bir Nil veya Eksileri ise, sadece iade edin.
- Thunk ise, bir Nil veya Eksileri için işlevini çağırın. Thunk'u Nil veya Cons ile değiştirin ve iade edin.
Not: Thunk'u zorunlu değeri ile değiştirmek “tembel” tanımının önemli bir parçasıdır . Bu adım atlanırsa, yukarıdaki Fibonacci algoritması çok yavaş olacaktır.
- boş - Bir Liste düğümünün Nil olup olmadığını görün (zorladıktan sonra).
- head (aka "car") - Bir listenin ilk maddesini al (veya eğer Nil ise uygun bir yere at).
- tail (aka "cdr") - Bir listenin başından sonraki öğeleri al (veya eğer Nil ise bir form at.)
- zipWith - İkili işlev (örn.
(+)
) ve iki (muhtemelen sonsuz) liste verildiğinde, işlevi listelerin ilgili öğelerine uygular. Örnek:
zipWith (+) [1,2,3] [1,1,10] == [2,3,13]
- almak - N sayısı ve (muhtemelen sonsuz) bir liste göz önüne alındığında, listenin ilk N öğesini alın.
- yazdır - Listedeki tüm öğeleri yazdırın. Uzun veya sınırsız bir liste verildiğinde bu adım adım çalışmalıdır.
fibs
kendisini kendi tanımında kullanır. Tembel özyineleme kurmak biraz zor; Böyle bir şey yapmanız gerekecek:- Bir thunk tahsis et
fibs
. Şimdilik kukla bir durumda bırakın. - Bir referansa bağlı olan thunk fonksiyonunu tanımlayın
fibs
. - Thunk işlevini ile güncelleyin.
Bu sıhhi tesisatı,
fix
Listeden döndürme işlevini çağıran ve kendi dönüş değerine sahip bir işlev tanımlayarak gizlemek isteyebilirsiniz . Kısa bir şekerleme yapmayı düşünün, böylece bu fikir ortaya çıkabilir.- Bir thunk tahsis et
Polimorfizm (herhangi bir öğe türü ile çalışma yeteneği) gerekli değildir, ancak bunu kendi dilinizde aptalca bir şekilde yapmanın bir yolunu bulabilecek olup olmadığına bakın.
- Bellek yönetimi konusunda endişelenmeyin. Çöp toplama özelliğine sahip dillerin bile bir daha asla kullanamayacağınız nesneleri (örneğin arama yığınında) taşıma eğilimi vardır, bu nedenle programınız sonsuz bir listeyi dolaşırken hafızadan sızarsa şaşırmayın.
Dilinizin özelliklerini karşılamak için bu yönergelerden biraz sapmaktan veya tembel listelere alternatif yaklaşımlar bulmaktan çekinmeyin.
Kurallar:
- İyi bilmediğiniz bir dil seçin. Buna, "onur-sistem" etiketine "ihtiyaç duymayacağım". Ancak, seçmenler hangi dillerde yayın yaptığınızı görmek için geçmişinizi kontrol edebilir.
Her şeyi yapmak için dilinizin yerleşik tembel liste desteğini kullanmayın. Önemli veya en azından ilginç bir şey yayınlayın.
Haskell hemen hemen dışarıda. Böyle bir şey yapmazsan, bu:
data List a = IORef (ListNode a) data ListNode a = Nil | Cons !a !(List a) | Thunk !(IO (ListNode a))
Not: Haskell'in katı olmayan değerlendirmesi sınırsız değildir, ancak tembel liste uygulamanızın özelliğini doğrudan oradan almaması gerekir. Aslında tembellik gerektirmeyen verimli, tamamen işlevsel bir çözüm görmek ilginç olurdu.
Python:
- İtertol kullanmayın.
- Jeneratörler gayet iyi, ancak bunları kullanıyorsanız, zorunlu değerleri not almak için bir yol bulmanız gerekecek.
zipWith (+) [1,2,3,4,5] [0,0,0] == [1,2,3]
,. Bununla birlikte, yukarıdaki Fibonacci algoritması için önemi yoktur, çünkü her iki zipWith argümanı sonsuz listelerdir.
fibs
Doğru uygulamak için özel bir şey yapmanız gerekiyor , çünkü kendinize bağlı. Tembel özyinelemeye odaklanmak için soruyu güncelledim. FUZxxl onu kendisi tarafından çözdü.
zipWith
Farklı uzunluklarda iki liste çağırırken davranış ne olmalıdır ?