2013-04-25 33 views
5

Từ Scala Martin Odersky của Tất nhiên tôi đã sau Tập thể dục (điều này một bài tập video trong đó câu trả lời được đưa ra):Object trong Scala

" Cung cấp một thực hiện các lớp trừu tượng Nat đại diện số nguyên không âm

không sử dụng các lớp học số tiêu chuẩn trong việc thực hiện này. Thay vào đó, thực hiện một sub-object và một sub-class.

một cho số không, người kia cho số đúng prositive. "

Đây là mã:

abstract class Nat { 
    def isZero : scala.Boolean 
    def predecessor : Nat 
    def successor = new Succ(this) 
    def + (that : Nat) : Nat 
    def - (that : Nat) : Nat 
} 

object Zero extends Nat { 
    def isZero = true 
    def predecessor = throw new Error("0.predecessor") 
    def + (that: Nat) = that 
    def - (that: Nat) = if(that.isZero) this else throw new Error("negative number") 
} 

class Succ(n : Nat) extends Nat { 
    def isZero = false 
    def predecessor = n 
    def +(that : Nat) = new Succ(n + that) 
    def -(that: Nat) = n - that.predecessor 
} 

Trong một bảng tính Scala tôi có:

object NatTests { 
    new Successor(Zero).+(new Successor(Zero)) 
} 

nào trả về một Sucessor mới. Tôi không nghĩ rằng tôi hiểu mã này hoàn toàn như tôi sẽ có thể thêm các đối tượng khác không có mã mở rộng? Nếu vậy, làm thế nào điều này được thực hiện?

+6

Đối với nền , hãy xem xét số học Peano và/hoặc số của Giáo hội để bạn hiểu khái niệm đang được triển khai ở đây. –

Trả lời

0

Bạn đang có khả năng nhất dự kiến ​​sẽ thực hiện chúng một cách đệ quy

Tôi không chắc chắn của các cú pháp chính xác, nhưng nó muốn được một cái gì đó như thế này

def +(that : Nat) = (this.predecessor + that.successor) 
def -(that: Nat) = if (that.isZero) this else (this.predecessor - that.predecessor) 

Cũng kể từ khi đối tượng của bạn là không thay đổi, không có lý do thực sự để tạo ra một cái mới mỗi lần.

0

Đó là cách tôi sẽ viết nó:

sealed trait Nat { 
    def isZero : scala.Boolean 
    def predecessor : Nat 
    def successor = Succ(this) 
    def + (that : Nat) : Nat 
    def - (that : Nat) : Nat = 
     if (that.isZero) this else this.predecessor - that.predecessor 
} 

case object Zero extends Nat { 
    def isZero = true 
    def predecessor = sys.error("predecessor of zero") 
    def + (that: Nat) = that 
} 

case class Succ(predecessor : Nat) extends Nat { 
    def isZero = false 
    def +(that : Nat) = this.predecessor + that.successor 
} 
3

Bạn thể thêm zero số không/đối tượng mà không cần mở rộng bất kỳ của các lớp Nat, Zero, hoặc Succ. Khi bạn sử dụng một đối tượng natObj loại Nat và xây dựng một đối tượng mới new Succ(natObject) đối tượng mới đại diện cho một số cao hơn số mà natObj đại diện.

Có lẽ việc có thể để xem các đối tượng, làm cho điều này rõ ràng hơn một chút:

abstract class Nat { 
    def isZero : Boolean 
    def predecessor : Nat 
    def successor = new Succ(this) 
    def + (that : Nat) : Nat 
    def - (that : Nat) : Nat 
} 

object Zero extends Nat { 
    def isZero = true 
    def predecessor = throw new Error("0.predecessor") 
    def + (that: Nat) = that 
    def - (that: Nat) = if(that.isZero) this else throw new Error("negative number") 

    override def toString = "0 => Zero" 
} 

class Succ(n : Nat) extends Nat { 
    def isZero = false 
    def predecessor = n 
    def + (that : Nat) = new Succ(n + that) 
    def - (that: Nat) = if (that.isZero) this else n - that.predecessor 

    override def toString = { 
    def findNumber(nat: Nat): Int = 
     if (nat.isZero) 0 
     else 1 + findNumber(nat.predecessor) 
    val number = findNumber(this) 
    String.valueOf(number) + " => " + 
      ((1 to number) fold ("Zero")) ((s,_) => "Succ(" + s + ")") 
    } 
} 

Bây giờ bảng Scala của bạn sẽ cho bạn thấy số một đối tượng đại diện và cấu trúc bên trong của nó:

object NatTests extends App { 
    val nat0 = Zero         
    val nat1 = new Succ(Zero)      
    val nat2 = new Succ(nat1) // or new Succ(new Succ(Zero)) 
    val nat3 = new Succ(nat2) // or new Succ(new Succ(new Succ(Zero))) 

    println(nat0)    //> 0 => Zero 
    println(nat1)    //> 1 => Succ(Zero) 
    println(nat2)    //> 2 => Succ(Succ(Zero)) 
    println(nat3)    //> 3 => Succ(Succ(Succ(Zero))) 
    println(nat2 + nat2)  //> 4 => Succ(Succ(Succ(Succ(Zero)))) 
    println(nat3 + nat2)  //> 5 => Succ(Succ(Succ(Succ(Succ(Zero))))) 
} 
+0

the to String thực sự hữu ích. vì vậy chúng tôi không bao giờ sử dụng số ở tất cả? bó của nó của các đối tượng dán lại với nhau? thay vì bit, chúng ta đang sử dụng ký hiệu để biểu diễn các số tự nhiên? wat có đang diễn ra ở đây không? – bicepjai

+0

@bicepjai: Vâng, đó là chính xác những gì đang xảy ra. Một số ngôn ngữ (nhưng không Scala) tối ưu hóa những "mã số nhà thờ" https://en.wikipedia.org/wiki/Church_encoding để chúng được lưu trữ nội bộ dưới dạng "bit" nhưng xuất hiện với lập trình viên là "các đối tượng được dán lại với nhau". – Tilo

+0

Tôi thực sự yêu tất cả cách puzzly của việc sử dụng tính toán lambda cho lập trình :) nhưng tôi có thời gian khó khăn để bọc tâm trí của tôi về cách này tốt hơn so với lập trình bắt buộc nói về hiệu quả? – bicepjai