2015-01-24 41 views
5

Scala'da bu kodun nasıl modelleneceğini merak ediyorum. Özyinelemeli işlev türleri nasıl oluşturulur?

Bu

golang içinde olduğunu ve bir özyinelemeli fonksiyon türüdür: Yani yukarıdaki

type walkFn func(*int) walkFn 

tip sadece bir Definition olduğu, gömme işlevi bir tamsayı için bir işaretçi alır bir fonksiyondur ve bir yürüyüş işlevi döndürür.

Bir örnek uygulama olacaktır:

func walkForward(i *int) walkFn { 
    *i += rand.Intn(6) 
    return pickRandom(walkEqual, walkBackward) 
} 

func walkBackward(i *int) walkFn { 
    *i += -rand.Intn(6) 
    return pickRandom(walkEqual, walkForward) 
} 

Burada böyle bir kod çalıştırabilir: http://play.golang.org/p/621lCnySmy

o Scala bu desen gibi bir şey yazmak mümkün mü?

cevap

5

Scala'nın üzücü gerçeklerinden biri, özyinelemeli tür takma adların desteklenmediğidir. Çoğaltma aşağıdaki Amaçlı şu sonuçları verir:

scala> type WalkFn = Function[Int, WalkFn] 
<console>:7: error: illegal cyclic reference involving type WalkFn 
     type WalkFn = Function[Int, WalkFn] 
           ^

başka not Ölçeği (genellikle ney, fonksiyonel programlama paradigmada tamamen nefret üzerine, hoş) tarafından başvuru değerlerini değiştirmek için izin vermez olmasıdır. Bununla birlikte, dehşete düşürmeyin! Başka seçenekler var. Özellikler kendi kendini referans alabilir ve fonksiyonlar sadece Scala'da sınıflar. Böylece genel özyinelemeli WalkFn'i özelliklerle modelleyebiliriz. Ayrıca, bir parametreyi referans olarak değiştirmek yerine, değişmez değerleri benimseyebilir ve işlevimizin bir sonraki ilerleyişe dönmesini sağlayabiliriz.

şu döngüsel başvurular içerdiğinden (WalkForward -> WalkBackward, WalkBackward -> vb WalkForward,), bunu Scala derleyici tüm derlemek olacak REPL önce şu örneği (çalıştırmanın skalası içine :paste yazmanız gerekir tek adımda 3 Walk{Forward,Backward,Equal} uygulamaları

İlk:.

import scala.util.Random 

object Helpers { 
    def pickRandom[A](items: A*) = 
    items(Random.nextInt(items.length)) 
} 

trait WalkFn extends (Int => (Int, WalkFn)) {} 

object WalkForward extends WalkFn { 
    def apply(i: Int) = 
    (i + Random.nextInt(6), 
     Helpers.pickRandom(WalkEqual, WalkBackward)) 
} 

object WalkEqual extends WalkFn { 
    def apply(i: Int) = 
    (i + (Random.nextInt(7) - 3), 
     Helpers.pickRandom(WalkForward, WalkBackward)) 
} 

object WalkBackward extends WalkFn { 
    def apply(i: Int) = 
    (Random.nextInt(6) - 3, 
     Helpers.pickRandom(WalkEqual, WalkForward)) 
} 

def doWalk(count: Int, walkFn: WalkFn = WalkEqual, progress: Int = 0): Unit = 
    if (count > 0) { 
    val (nextProgress, nextStep) = walkFn(progress) 
    println(nextProgress) 
    doWalk(count - 1, nextStep, nextProgress) 
    } 

doWalk(20) 
0123:

Şimdi
$ scala 
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

, kodu yapıştırın

Daha sonra, talimatlara göre ctrl-D numaralı telefona tıklayın.

Fonksiyonel sarhoş stagger'ın tadını çıkarın!

+0

Güzel cevap ama (değil * Henüz * Scala ile aşina olmak): 'Helpers' nesnesine ne için ihtiyacınız var? Bu sadece bir isim mi, yoksa herhangi bir kongre sizi üst düzey bir 'def' i yapmamanızı engelliyor mu? – Bergi

+3

@Bergi all 'def'' scala'daki yöntemlerdir (bunlar açıkça/örtük olarak işlev nesnelerine eta-genişletme yoluyla dönüştürülür). Yani her yöntem bazı nesnelerin içine yerleştirilir. Bu arada, Scala REPL (ve dahili yorumlayıcının kendisi) sentetik bir nesne yaratır, bu nedenle REPL döngüsünün hemen içinde yöntemleri tanımlayabilirsiniz, ancak insanlar genellikle kodları scalac tarafından derlenmiş olarak derlenmeye hazır hale getirmek için nesneleri kullanırlar. – dk14

5

Scala'da yinelemeli bölümü hesaba katmak için daha deyimsel olduğunu söyleyebilirim. Yani, örneğin bir devlet makinesini tanımlayabilirsiniz:

import scala.util.Random 

sealed trait Walker { 
    def i: Int 
    def advance: Walker 
} 

case class WalkEqual(i: Int) extends Walker { 
    def advance = { 
    val next = i + Random.nextInt(7) - 3 
    if (Random.nextBoolean) WalkForward(next) else WalkBackward(next) 
    } 
} 

case class WalkForward(i: Int) extends Walker { 
    def advance = { 
    val next = i + Random.nextInt(6) 
    if (Random.nextBoolean) WalkEqual(next) else WalkBackward(next) 
    } 
} 

case class WalkBackward(i: Int) extends Walker { 
    def advance = { 
    val next = i - Random.nextInt(6) 
    if (Random.nextBoolean) WalkEqual(next) else WalkForward(next) 
    } 
} 

Sonra aşağıdaki yazabiliriz:

val locations = Stream.iterate[Walker](WalkEqual(0))(_.advance).map(_.i) 

Bu yerlerde bizim yürüteç ziyaret sonsuz akışıdır. Bu gibi kullanabilirsiniz:

scala> locations.take(10).foreach(println) 
0 
0 
-1 
2 
1 
0 
-5 
-5 
-10 
-6 

Biz de locations.take(100).toList yazarak bu sınırlı sayıda alıp (örneğin liste olarak) bir somut-gerçekleşmiştir koleksiyonunda onları toplamak olabilir.

+0

Bir sınıfa sahip olmak mümkün mü ve daha sonra WalkEqual, WalkForward gibi metotlar örnek derslere sahip olmaktan mı geliyor? – Blankman

+0

Başka bir geçerli yaklaşım, ancak bu durum daha az jenerik olmanın dezavantajına sahiptir (mevcut işlev türünü kullanmak yerine, yeni bir tür oluşturduk.) Artık işlevler ve işlevleri alan şeyler üzerinde tanımlanan işlemleri kaybederiz. –

8

Bu mümkün.Sen Scala'nın döngüsel başvuru kısıtlaması "hile" varoluşsal türlerinden bazıları:

type A[T <: A[_]] = Int => (Int, T) 

lazy val walkEqual: A[A[_]] = (i: Int) => 
    (i + Random.nextInt(7) - 3, if (Random.nextBoolean) walkForward else walkBackward) 

lazy val walkForward: A[A[_]] = (i: Int) => 
    (i + Random.nextInt(6), if (Random.nextBoolean) walkEqual else walkBackward) 

lazy val walkBackward: A[A[_]] = (i: Int) => 
    (i - Random.nextInt(6), if (Random.nextBoolean) walkEqual else walkForward) 

def doWalk(count: Int, walkFn: A[_] = walkEqual, progress: Int = 0): Unit = 
    if (count > 0) { 
    val (nextProgress, nextStep: A[_] @unchecked) = walkFn(progress) 
    println(nextProgress) 
    doWalk(count - 1, nextStep, nextProgress) 
    } 

Sonuç:

scala> doWalk(10) 
2 
5 
2 
0 
-3 
-5 
-4 
-8 
-8 
-11 

Veya benzeri @Travis Kahverengi ek olarak:

val locations = Stream.iterate[(Int,A[_] @unchecked)](walkEqual(0)) { 
    case (x: Int, f: A[_]) => f(x) 
}.map(_._1) 

scala> locations.take(20).toList 
res151: List[Int] = List(-1, 1, 1, 4, 1, -2, 0, 1, 0, 1, 4, -1, -2, -4, -2, -1, 2, 1, -1, -2) 
+0

Detaylı olarak ilk satırı detaylı olarak açıklayabilir misiniz? T, A'nın bir alt sınıfıdır, fakat A [_} ne demektir? A'nın girdi ve çıktısının ne olduğu konusunda açık olabilir misiniz? Kolayca karıştıyorum :) – Blankman

+3

'A [_]' burada tanımsız bir sınırlama anlamına gelen varoluşsal bir türüdür. Yani, 'A [T: dk14

İlgili konular