Scala:泛型和隐式
Scala: generics and implicit
我必须开发 class StackMachine[T]。如果 T = Boolean,那么应该有逻辑操作。如果 T = Int、Double、Long 等,应该有算术运算。首先我开发了 class Stack[T].
class Stack[T](val stack: List[T]) {
val length: Int = stack.length
def isEmpty: Boolean = {length == 0}
def push(x: T): Stack[T] = {
new Stack[T](x :: stack)
}
def peak: T = {
if (this.isEmpty)
throw new ArrayIndexOutOfBoundsException
else stack.head
}
def pop(): Stack[T] = {
if (this.isEmpty)
throw new ArrayStoreException()
val x :: xs = stack
new Stack[T](xs)
}
最重要的是我不知道如何开发 StackMachine[T] 操作的存在取决于类型。
我试过这个:
case class StackMachine[T](val stack:Stack[T]){
def const(x: T): StackMachine[T] = {new StackMachine[T](new Stack[T](this.stack.push(x).stack))}
def dup: StackMachine[T] = {new StackMachine[T](new Stack[T](this.stack.push(this.stack.peak).stack))}
def swap: StackMachine[T] = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.peak
val finalStack = secondStack.pop().push(startPeak)
StackMachine[T](stack)
}
def and(): StackMachine[Boolean] = {
val startStack = this.stack.asInstanceOf[Stack[Boolean]]
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.peak
StackMachine[Boolean](new Stack[Boolean](secondStack.push(startPeak && secondPeak).stack))
}
def or: StackMachine[Boolean] = {
val startStack = this.stack.asInstanceOf[Stack[Boolean]]
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.pop().peak
StackMachine[Boolean](new Stack[Boolean](secondStack.push(startPeak || secondPeak).stack))
}
def xor: StackMachine[Boolean] = {
val startStack = this.stack.asInstanceOf[Stack[Boolean]]
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.pop().peak
StackMachine[Boolean](new Stack[Boolean](secondStack.push(startPeak ^ secondPeak).stack))
}
def sum(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.plus(startPeak,input)).stack))
}
def dif(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.minus(startPeak,input)).stack))
}
def mul(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.toDouble(startPeak).*(N.toDouble(input)).asInstanceOf[T]).stack))
}
def div(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.toDouble(startPeak)./(N.toDouble(input)).asInstanceOf[T]).stack))
}
def min(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.min(startPeak,input)).stack))
}
def max(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.max(startPeak,input)).stack))
}
}
但这是错误的,因为操作不应该有输入参数,因为所有变量都必须从堆栈中获取。更重要的是,这样我就无法创建 diff 和 mul 函数。
我想使 StackMachine[T] 抽象并使用 imlplicit 对象,但失败了,因为在那种情况下,我的函数不能 return StackMachine。可能是我对隐含的理解不够好,或者有另一种方法可以做到这一点?
那么是的,似乎该项目旨在使用 typeclass.
来解决
例如,查看 布尔值 的这个小例子 and
:
sealed trait BehavesAsBoolean[T] {
def and(t1: T, t2: T): T
}
object BehavesAsBoolean {
implicit final val BooleanBehavesAsBoolean: BehavesAsBoolean[Boolean] =
new BehavesAsBoolean[Boolean] {
override def and(b1: Boolean, b2: Boolean): Boolean =
b1 && b2
}
}
final class StackMachine[T](stack: Stack[T]) {
def and(implicit ev: BehavesAsBoolean[T]): Option[StackMachine[T]] =
for {
// I changed the implementation of pop to return an Option[(T, Stack[T])]
(b1, s2) <- stack.pop
(b2, s3) <- s2.pop
} yield {
new StackMachine(s3.push(ev.and(b1, b2)))
}
}
当然,你可能还是更喜欢抛出异常而不是使用Option
不管怎样,我希望这能帮助你完成代码。
可以看到代码运行 here.
我必须开发 class StackMachine[T]。如果 T = Boolean,那么应该有逻辑操作。如果 T = Int、Double、Long 等,应该有算术运算。首先我开发了 class Stack[T].
class Stack[T](val stack: List[T]) {
val length: Int = stack.length
def isEmpty: Boolean = {length == 0}
def push(x: T): Stack[T] = {
new Stack[T](x :: stack)
}
def peak: T = {
if (this.isEmpty)
throw new ArrayIndexOutOfBoundsException
else stack.head
}
def pop(): Stack[T] = {
if (this.isEmpty)
throw new ArrayStoreException()
val x :: xs = stack
new Stack[T](xs)
}
最重要的是我不知道如何开发 StackMachine[T] 操作的存在取决于类型。 我试过这个:
case class StackMachine[T](val stack:Stack[T]){
def const(x: T): StackMachine[T] = {new StackMachine[T](new Stack[T](this.stack.push(x).stack))}
def dup: StackMachine[T] = {new StackMachine[T](new Stack[T](this.stack.push(this.stack.peak).stack))}
def swap: StackMachine[T] = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.peak
val finalStack = secondStack.pop().push(startPeak)
StackMachine[T](stack)
}
def and(): StackMachine[Boolean] = {
val startStack = this.stack.asInstanceOf[Stack[Boolean]]
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.peak
StackMachine[Boolean](new Stack[Boolean](secondStack.push(startPeak && secondPeak).stack))
}
def or: StackMachine[Boolean] = {
val startStack = this.stack.asInstanceOf[Stack[Boolean]]
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.pop().peak
StackMachine[Boolean](new Stack[Boolean](secondStack.push(startPeak || secondPeak).stack))
}
def xor: StackMachine[Boolean] = {
val startStack = this.stack.asInstanceOf[Stack[Boolean]]
val startPeak = startStack.peak
val secondStack = startStack.pop()
val secondPeak = secondStack.pop().peak
StackMachine[Boolean](new Stack[Boolean](secondStack.push(startPeak ^ secondPeak).stack))
}
def sum(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.plus(startPeak,input)).stack))
}
def dif(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.minus(startPeak,input)).stack))
}
def mul(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.toDouble(startPeak).*(N.toDouble(input)).asInstanceOf[T]).stack))
}
def div(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.toDouble(startPeak)./(N.toDouble(input)).asInstanceOf[T]).stack))
}
def min(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.min(startPeak,input)).stack))
}
def max(input : T)(implicit N: Numeric[T]) = {
val startStack = this.stack
val startPeak = startStack.peak
val secondStack = startStack.pop()
StackMachine[T](new Stack[T](secondStack.push(N.max(startPeak,input)).stack))
}
}
但这是错误的,因为操作不应该有输入参数,因为所有变量都必须从堆栈中获取。更重要的是,这样我就无法创建 diff 和 mul 函数。 我想使 StackMachine[T] 抽象并使用 imlplicit 对象,但失败了,因为在那种情况下,我的函数不能 return StackMachine。可能是我对隐含的理解不够好,或者有另一种方法可以做到这一点?
那么是的,似乎该项目旨在使用 typeclass.
来解决例如,查看 布尔值 的这个小例子 and
:
sealed trait BehavesAsBoolean[T] {
def and(t1: T, t2: T): T
}
object BehavesAsBoolean {
implicit final val BooleanBehavesAsBoolean: BehavesAsBoolean[Boolean] =
new BehavesAsBoolean[Boolean] {
override def and(b1: Boolean, b2: Boolean): Boolean =
b1 && b2
}
}
final class StackMachine[T](stack: Stack[T]) {
def and(implicit ev: BehavesAsBoolean[T]): Option[StackMachine[T]] =
for {
// I changed the implementation of pop to return an Option[(T, Stack[T])]
(b1, s2) <- stack.pop
(b2, s3) <- s2.pop
} yield {
new StackMachine(s3.push(ev.and(b1, b2)))
}
}
当然,你可能还是更喜欢抛出异常而不是使用Option
不管怎样,我希望这能帮助你完成代码。
可以看到代码运行 here.