Cách hiệu quả nhất là lưu trữ số nguyên thủy (Int Double ...) làm loại thô.
Không được lưu trữ unsignness trong thông số Loại, sẽ bị xóa khi chạy. Scala thực hiện điều này khi bạn để các trường hợp đơn giản mở rộng AnyVal.
Mã folowing thực hiện điều này cho Ints, Longs, Doubles và Bigint. Tôi đã thêm một vài phân loại trong adition để unsigned và đổi tên unsigned thành tích cực.
Cũng vì việc phân loại được thực hiện trong hệ thống kiểu, chúng tôi không cần cung cấp quá nhiều hàm + - và * quá tải. Điều này sẽ tiết kiệm không gian khi cố gắng thực hiện điều này cho tất cả các loại số.
Vẫn còn một chút việc cần thực hiện khi kết nối giữa các loại khác nhau. Tôi sẽ xem xét điều này sau.
Các đặc điểm phân loại:
sealed trait SignTag{
type SubTag <:SignTag;
type AddTag <:SignTag;
type MultTag<:SignTag;
}
sealed trait Signed extends SignTag{
type SubTag=Signed;
type AddTag=Signed;
type MultTag=Signed;
}
sealed trait Positive extends SignTag{
type SubTag=Signed;
type AddTag=Negative;
type MultTag=Negative;
}
sealed trait Negative extends SignTag{
type SubTag=Signed;
type AddTag=Negative;
type MultTag=Positive;
}
sealed trait Zero extends SignTag{
type SubTag=Zero;
type AddTag=Zero;
type MultTag=Zero;
}
Int wrapper:
object SInt {
@inline
implicit def toSigned[T <: SignTag](int:SInt[T]):SInt[Signed]=int.asInstanceOf[SInt[Signed]];
@inline implicit def toLong[T <: SignTag](int:SInt[T]):SLong[T]=SLong(int.underlying);
@inline implicit def toDouble[T <: SignTag](int:SInt[T]):SDouble[T]=SDouble(int.underlying);
@inline implicit def toBig[T <: SignTag](int:SInt[T]):SBigInt[T]=SBigInt(int.underlying);
}
case class SInt[T <: SignTag](val underlying:Int) extends AnyVal{
def -(second: SInt[_ <: T#InTag]):SInt[T#SubTag]=new SInt[T#SubTag](underlying - second.underlying);
def +(second: SInt[_ <: T#InTag]):SInt[T#AddTag]=new SInt[T#AddTag](underlying + second.underlying);
def *(second: SInt[_ <: T#InTag]):SInt[T#MultTag]=new SInt[T#MultTag](underlying * second.underlying);
def assertSameType(other:SInt[T])={};
}
dài wrapper:
object SLong {
@inline
implicit def toSigned[T <: SignTag](int:SLong[T]):SLong[Signed]=int.asInstanceOf[SLong[Signed]];
@inline implicit def toDouble[T <: SignTag](int:SLong[T]):SDouble[T]=SDouble(int.underlying);
@inline implicit def toBig[T <: SignTag](int:SLong[T]):SBigInt[T]=SBigInt(int.underlying);
}
case class SLong[T <: SignTag](val underlying:Long) extends AnyVal{
def -(second: SLong[_ <: T#InTag]):SLong[T#SubTag]=new SLong[T#SubTag](underlying - second.underlying);
def +(second: SLong[_ <: T#InTag]):SLong[T#AddTag]=new SLong[T#AddTag](underlying + second.underlying);
def *(second: SLong[_ <: T#InTag]):SLong[T#MultTag]=new SLong[T#MultTag](underlying * second.underlying);
def assertSameType(other:SLong[T])={};
}
đúp wrapper:
object SDouble {
@inline
implicit def toSigned[T <: SignTag](int:SDouble[T]):SDouble[Signed]=int.asInstanceOf[SDouble[Signed]];
}
case class SDouble[T <: SignTag](val underlying:Double) extends AnyVal{
def -(second: SDouble[_ <: T#InTag]):SDouble[T#SubTag]=new SDouble[T#SubTag](underlying - second.underlying);
def +(second: SDouble[_ <: T#InTag]):SDouble[T#AddTag]=new SDouble[T#AddTag](underlying + second.underlying);
def *(second: SDouble[_ <: T#InTag]):SDouble[T#MultTag]=new SDouble[T#MultTag](underlying * second.underlying);
def assertSameType(other:SDouble[T])={};
}
bigint wrapper:
object SBigInt {
@inline
implicit def toSigned[T <: SignTag](int:SLong[T]):SLong[Signed]=int.asInstanceOf[SLong[Signed]];
@inline
implicit def toDouble[T <: SignTag](int:SBigInt[T]):SDouble[T]=SDouble(int.underlying.toDouble);
}
case class SBigInt[T <: SignTag](val underlying:BigInt) extends AnyVal{
def -(second: SBigInt[_ <: T#InTag]):SBigInt[T#SubTag]=new SBigInt[T#SubTag](underlying - second.underlying);
def +(second: SBigInt[_ <: T#InTag]):SBigInt[T#AddTag]=new SBigInt[T#AddTag](underlying + second.underlying);
def *(second: SBigInt[_ <: T#InTag]):SBigInt[T#MultTag]=new SBigInt[T#MultTag](underlying * second.underlying);
def assertSameType(other:SBigInt[T])={};
}
Kiểm tra cú pháp:
class CompileToTest {
val signed=new SInt[Signed](5);
val positive=new SInt[Positive](5);
val negative=new SInt[Negative](-5);
val zero=new SInt[Zero](0);
(signed + signed).assertSameType(signed);
(negative + signed).assertSameType(signed);
(positive - positive).assertSameType(signed);
(positive * negative).assertSameType(signed);
(zero + zero).assertSameType(zero);
val positiveDouble=SDouble[Positive](4.4)
val negativeDouble=SDouble[Negative](-4.4)
val signedDouble=SDouble[Signed](-4.4)
(positiveDouble * negativeDouble).assertSameType(signedDouble);
}
Ps. Đã không thực sự nhìn vào bytecode, nhưng các tài liệu sugests rằng điều này nên được inlined và biên dịch xuống nguyên thủy.
Tôi chỉ thích lanuage này.
Vì vậy, tôi đã nghĩ về cách tiếp cận này - Ocaml sử dụng tất cả thời gian trong các mô-đun của họ. Làm thế nào để thực hiện chữ ký trên những thứ như '+', '-',' * '? Bạn có kiểu 'A' được trả về cho tất cả các hàm đó không? Điều đó dẫn đến câu hỏi về cách người dùng cuối thực sự truy cập vào loại cơ bản như thế nào? Một số hàm (a: A):? –
Cũng có 'cơ bản' trong một phạm vi đóng gói loại trừ phạm vi công khai? Tôi đang ở hàng rào mà tôi đoán ... –
Chỉnh sửa với một số suy nghĩ khác. Tôi đoán bạn sẽ phải quyết định xem bạn muốn loại/giá trị cơ bản được tiếp xúc hay không. Tôi cho rằng bạn cũng có thể cân nhắc tạo một lớp kiểu 'Số' thay vì sử dụng thừa kế. –