加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

使用类型成员减少Scala中的类型冗长度是否可行?

发布时间:2020-12-16 09:15:58 所属栏目:安全 来源:网络整理
导读:所以,这可能听起来像是一个关于语言设计的一般问题,但我认为这里有一些具体的东西.具体来说,我感兴趣的是什么技术挑战阻止通常使用的kludgy代码. 我们都知道,“Scala的类型推论不如Haskell的那样好”,而且有很多原因,它不能那么好,而且仍然是Scala所做的一切
所以,这可能听起来像是一个关于语言设计的一般问题,但我认为这里有一些具体的东西.具体来说,我感兴趣的是什么技术挑战阻止通常使用的kludgy代码.

我们都知道,“Scala的类型推论不如Haskell的那样好”,而且有很多原因,它不能那么好,而且仍然是Scala所做的一切.但是,在Scala编程足够长的时间之后,也是显而易见的,那么差的类型推断并不是那么糟糕,所以指定一些常见类型所需的冗长度也是如此.所以,例如,在多态尾函数中,

def tail[A](ls: List[A]) =
    ls match {
        case Nil     => sys.error("Empty list")
        case x :: xs => xs
    }

为了使该方法有用,需要明确命名一个类型参数;没有办法. tail(ls:List [Any])将不起作用,因为Scala无法确定输出类型的结果类型是一样的,即使对于人来说这是“显而易见的”.

所以,受到这个困难的启发,并且知道Scala有时可以比类型成员更聪明,而不是类型参数,我写了一个使用类型成员的List的版本:

sealed trait TMList {
    self =>
    type Of
    def :::(x: Of) = new TMCons {
        type Of = self.Of
        val head = x
        val tail = (self: TMList { type Of = self.Of })
    }
}
abstract class TMNil extends TMList
def ATMNil[A] = new TMNil { type Of = A }
abstract class TMCons extends TMList {
    self =>
    val head: Of
    val tail: TMList { type Of = self.Of }
}

好的,定义看起来很可怕,但它至少是直截了当的,它允许我们编写我们的尾部方法如下:

def tail4(ls: TMList) =
    ls match {
        case _: TMNil => sys.error("Empty list")
        case c: TMCons with ls.type => c.tail
    }

美丽的是,这是有效的,所以我们可以写(按照你的期望定义)

val ls = 1 ::: 2 ::: ATMNil
val a = tail4(ls)
println(head4(a) * head4(a))

而Scala知道输出类型成员仍然是Int.我们不得不使用ls.type写一些有趣的TMCons,而Scala则抱怨说这个比赛并不详尽,但是这个代码可能只是被Scala插入我们的,因为当你在任何情况下必须是ls.type,当然匹配是穷尽的.

所以我的问题是:有什么东西?为什么我们不这样做所有的多态类型,只是修改语言,使语法看起来不那么糟糕?我们遇到什么技术问题?

显然有一个问题是类不能在其类型成员中是协变的;但我对此并不感兴趣我认为这是一个单独的问题.假设我们不关心方差.还有什么问题吗?

我怀疑这可能会引入类型推理的新问题(就像我必须如何定义ATMNil的例子一样),但是我不明白Scala的类型推断能够很好地知道那些是什么.

编辑回应0__:我想你可能已经找到了.具有类型参数的版本可以工作,

def move2[A](a: TMList { type Of = A },b: TMList { type Of = A }) = b match {
    case c: TMCons with b.type => c.head ::: a
    case _                     => a
}

但有趣的是,没有明确的返回类型,一个咖喱的依赖类型的版本不会:

def move3(a: TMList)(b: TMList { type Of = a.Of }) = b match {
    case c: TMCons with b.type => c.head ::: a
    case _                     => a
}

Scala推测返回类型为TMList;这是两种类型的上限,TMList {type Of = a.Of}和a.type.当然,TMList {type Of = a.Of}也将是一个上限(和我想要的一个),这就是为什么添加一个显式返回类型的工作原理),而且我认为一个更具体的上界.我不知道为什么Scala不会推断出更具体的上限.

解决方法

尝试用TMList重写以下内容:

def move[A](a: List[A],b: List[A]): List[A] = b match {
   case head :: _ => head :: a
   case _ => a
}

move(List(1,2,3),List(4,5,6))

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读