为什么喜欢构图而不是继承呢?每种方法都有哪些权衡取舍?什么时候应该选择继承而不是作文?
我听说Liskov替换原则(LSP)是面向对象设计的基本原则.它是什么以及它的使用例子是什么?
oop liskov-substitution-principle definition design-principles solid-principles
Eric Lippert对这个问题的评论让我彻底糊涂了.C#中的转换和转换有什么区别?
我的一个朋友上周提出了一个看似无害的Scala语言问题,我没有得到一个好的答案:是否有一种简单的方法来声明属于某些常见类型类的东西的集合.当然,Scala中没有关于"类型类"的一流概念,因此我们必须从特征和上下文界限(即暗示)来考虑这一点.
具体地说,给定一些T[_]表示类型类型和类型的特征A,B并且C在范围内具有相应的含义T[A],T[B]并且T[C],我们希望声明类似于a的东西List[T[a] forAll { type a }],我们可以在其中抛出实例A,B并且C不受惩罚.这当然在Scala中不存在; 去年的一个问题更深入地讨论了这个问题.
自然的后续问题是"Haskell如何做到这一点?" 那么,GHC尤其具有称为impredicative polymorphism的类型系统扩展,在"Boxy Types"论文中有所描述.简而言之,给定一个类型类,T可以合法地构建一个列表[forall a. T a => a].给定这种形式的声明,编译器会执行一些字典传递魔术,它允许我们在运行时保留与列表中每个值的类型相对应的类型类实例.
事实是,"字典传递魔法"听起来很像"vtables".在像Scala这样的面向对象语言中,子类型是一种比"Boxy类型"方法更简单,更自然的机制.如果我们的A,B以及C所有延伸的特性T,那么我们可以简单地宣布List[T]并且快乐.同样,作为万里注意到,在评论下面,如果他们都继承特质T1,T2并且T3然后我可以使用List[T1 with T2 with T3]作为等同于impredicative哈斯克尔[forall a. (T1 …
haskell functional-programming scala subtype impredicativetypes
Haskell被称为"纯函数式语言".
在这种情况下,"纯粹"意味着什么?这对程序员有什么影响?
List("a").contains(5)
Run Code Online (Sandbox Code Playgroud)
因为a Int永远不会包含在列表中String,所以这应该在编译时生成错误,但事实并非如此.
它浪费并默默地测试String列表中包含的每个内容的相等性5,这些内容永远不会成立(在Scala中"5"永远不等于5).
这被称为" '包含'问题 ".而一些人暗示,如果一个类型系统无法正确地输入这样的语义,那么为什么要经过强制执行类型的额外的努力.所以我认为这是一个需要解决的重要问题.
类型参数化B >: A的List.contains输入的任何类型的是该类型的超类型A(包含在列表中的元素的类型).
trait List[+A] {
def contains[B >: A](x: B): Boolean
}
Run Code Online (Sandbox Code Playgroud)
此类型参数化是必要的,因为+A声明列表在类型上是协变的A,因此A不能在逆变位置中使用,即作为输入参数的类型.协变列表(必须是不可变的)对于扩展比强制列表(可以是可变的)更强大.
A是String在上面的例子有问题,但Int不是的超类型String,所以发生了什么事?该隐含包容 Scala中,决定Any是两者的相互超String和Int.
Scala的创建者Martin Odersky 建议修复将限制输入类型B仅限于那些具有equals方法的类型Any.
trait List[+A] …Run Code Online (Sandbox Code Playgroud) haskell ×2
oop ×2
scala ×2
aggregation ×1
c# ×1
casting ×1
composition ×1
contains ×1
covariance ×1
definition ×1
inheritance ×1
liskov-substitution-principle ×1
list ×1
paradigms ×1
subtype ×1
terminology ×1