我已经阅读了一些我可以在互联网上找到的关于多态性的文章.但我认为我无法理解它的含义及其重要性.大多数文章没有说明为什么它很重要以及如何在OOP中实现多态行为(当然在JavaScript中).
我无法提供任何代码示例,因为我还没有想到如何实现它,所以我的问题如下:
我有这个例子.但是很容易理解这段代码会产生什么结果.它没有给出关于多态性本身的任何清晰的想法.
function Person(age, weight) {
this.age = age;
this.weight = weight;
this.getInfo = function() {
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo.";
}
}
function Employee(age, weight, salary) {
this.salary = salary;
this.age = age;
this.weight = weight;
this.getInfo = function() {
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" …Run Code Online (Sandbox Code Playgroud) javascript oop polymorphism functional-programming parametric-polymorphism
其他潜在贡献者请注意:请不要犹豫,使用抽象或数学符号来表达您的观点.如果我发现你的答案不清楚,我会要求澄清,但你可以随意以舒适的方式表达自己.
要明确:我不是在寻找"安全" head,也不是head特别有意义的选择.问题的关键在于讨论head和讨论,并head'提供了背景.
我几个月来一直在用Haskell进行攻击(直到它已经成为我的主要语言),但我对一些更先进的概念以及语言哲学的细节都不了解(尽管我非常愿意学习).那么我的问题不是技术问题(除非它是,我只是没有意识到),因为它是一种哲学.
对于这个例子,我说的是head.
我想你会知道,
Prelude> head []
*** Exception: Prelude.head: empty list
Run Code Online (Sandbox Code Playgroud)
这是从head :: [a] -> a.很公平.显然,一个人不能返回(挥手)没有类型的元素.但与此同时,定义它很简单(如果不是微不足道的话)
head' :: [a] -> Maybe a
head' [] = Nothing
head' (x:xs) = Just x
Run Code Online (Sandbox Code Playgroud)
我见过一些这方面的讨论很少在这里的某些语句的注释部分.值得注意的是,一位Alex Stangl说
"有充分的理由不让一切都"安全",并在违反前提条件时抛出异常.
我不一定质疑这个断言,但我很好奇这些"好理由"是什么.
此外,保罗约翰逊说,
'例如你可以定义"safeHead :: [a] - >也许是",但现在不是处理空列表或证明它不会发生,你必须处理"没什么"或证明它不会发生".
我从该评论中读到的语气表明,这是难度/复杂度/事物的显着增加,但我不确定我是否掌握了他在那里推出的内容.
一位Steven Pruzina说(2011年,不低于),
"有一个更深层次的原因,例如'head'不能防止崩溃.要进行多态而处理空列表,'head'必须始终返回任何特定空列表中不存在的类型变量.它将是Delphic如果Haskell能做到这一点......".
允许空列表处理会导致多态性丢失吗?如果是这样,怎么样,为什么?是否有特殊情况会使这一点变得明显?本节由@Russell O'Connor充分回答.当然,任何进一步的想法都会受到赞赏.
我会根据清晰度和建议来编辑这个.您可以提供的任何想法,论文等都将非常感激.
我很确定他们不一样.然而,我被"Rust不支持"高级类型(HKT)的常见概念所困扰,而是提供参数多态性.我试图了解这一点并理解它们之间的区别,但却变得越来越纠结.
根据我的理解,Rust中有更高级的类型,至少是基础知识.使用"*" - 符号,HKT确实有一种例如* -> *.例如,Maybe是善良的* -> *,可以在Haskell中像这样实现.
data Maybe a = Just a | Nothing
Run Code Online (Sandbox Code Playgroud)
这里,
Maybe 是一个类型构造函数,需要应用于具体类型才能成为类型"*"的具体类型.Just a并且Nothing是数据构造函数.在关于Haskell的教科书中,这通常被用作高级类型的示例.但是,在Rust中它可以简单地实现为枚举,毕竟它是一个和类型:
enum Maybe<T> {
Just(T),
Nothing,
}
Run Code Online (Sandbox Code Playgroud)
区别在哪里?据我所知,这是一个更好的类型的完美的例子.
Maybe枚举资格作为一个HKT?在查看函数时,这种混淆仍在继续,我可以编写一个参数函数,它Maybe可以将HKT作为函数参数.
fn do_something<T>(input: Maybe<T>) {
// implementation
}
Run Code Online (Sandbox Code Playgroud)
再次,在Haskell中会是这样的
do_something :: Maybe a -> ()
do_something :: Maybe a -> ()
do_something _ = ()
Run Code Online (Sandbox Code Playgroud)
这导致了第四个问题.
haskell type-theory higher-kinded-types rust parametric-polymorphism
我已经看到了一些用于rank-2多态性的用例(最突出的例子是ST monad),但是没有比这更高级别的用例.有谁知道这样的用例?
polymorphism haskell types higher-rank-types parametric-polymorphism
许多静态类型语言具有参数多态性.例如在C#中,可以定义:
T Foo<T>(T x){ return x; }
Run Code Online (Sandbox Code Playgroud)
在呼叫站点中,您可以:
int y = Foo<int>(3);
Run Code Online (Sandbox Code Playgroud)
这些类型有时也像这样写:
Foo :: forall T. T -> T
Run Code Online (Sandbox Code Playgroud)
我听过有人说"forall就像类型级别的lambda抽象".所以Foo是一个函数,它接受一个类型(例如int),并产生一个值(例如int - > int类型的函数).许多语言推断出类型参数,因此您可以编写Foo(3)而不是Foo<int>(3).
假设我们有一个f类型的对象forall T. T -> T.我们可以用这个对象做的是首先通过Q写入传递它f<Q>.然后我们得到一个类型的值Q -> Q.但是,某些f是无效的.例如f:
f<int> = (x => x+1)
f<T> = (x => x)
Run Code Online (Sandbox Code Playgroud)
因此,如果我们"调用",f<int>那么我们会返回一个带有类型的值,int -> int一般来说,如果我们"调用",f<Q>那么我们会返回一个带有类型的值Q -> Q,这样就很好了.但是,人们普遍认为这f不是一种有效的类型forall T. T -> T,因为它根据您传递的类型做了 …
ocaml haskell types existential-type parametric-polymorphism
我在我的大学开设了高级编程课程,我对理解这段代码的工作方式有点麻烦.
public final class GenericClass<T> {
private void overloadedMethod(Collection<?> o) {
System.out.println("Collection<?>");
}
private void overloadedMethod(List<Number> o) {
System.out.println("List<Number>");
}
private void overloadedMethod(ArrayList<Integer> o) {
System.out.println("ArrayList<Integer>");
}
public void method(List<T> l) {
overloadedMethod(l);
}
public static void main(String[] args) {
GenericClass<Integer> test = new GenericClass<Integer>();
test.method(new ArrayList<Integer>());
}
}
Run Code Online (Sandbox Code Playgroud)
为什么这段代码会打印"Collection <?>"?
我是Go新手,但我读过Go常规不会错过参数多态.每当我尝试学习一门新语言时,我都会使用L99问题列表来进行练习.
即使我尝试写一些像第一个问题一样简单(在Go中将是单个语句,取一个切片的最后一个元素),我将如何将其写为一个接受任何类型切片的函数(使用我上面引用的那个单一语句)返回该切片的最后一个元素?
我认为即使语言没有参数多态,也必须有一些惯用的"Go"方式,以便Go常规声称他们不会错过参数多态.否则,如果示例比例如列表的最后一个元素更复杂,则需要一个函数来为每个类型执行任务.
我错过了什么?
考虑以下一对函数定义,它们传递类型检查器:
a :: forall a. a
a = undefined
b :: Int
b = a
Run Code Online (Sandbox Code Playgroud)
即类型的表达式forall a. a可用于Int期望类型之一的类型.这在我看来很像子类型,但据称Haskell的类型系统缺少子类型.这些形式的可替代性有何不同?
这个问题并不具体forall a. a.其他例子包括:
id :: forall a. a -> a
id x = x
idInt :: Int -> Int
idInt = id
Run Code Online (Sandbox Code Playgroud) 解决“ f = f(<*>)pure”类型提示了这一点,该类型讨论了一个更复杂的示例,但该示例也有效。
以下定义可以毫无问题地进行编译:
w :: Integral a => a
w = fromInteger w
Run Code Online (Sandbox Code Playgroud)
...当然,它在运行时无法正常工作,但这是个问题。问题的关键是,定义w本身使用的专用版本的w :: Integer。显然,这是一个合适的实例,因此进行类型检查。
但是,如果我们删除签名,那么GHC不会推断上述类型,而只能推断具体类型:
w' = fromInteger w'
Run Code Online (Sandbox Code Playgroud)
GHCi> :t w
w :: Integral a => a
GHCi> :t w'
w' :: Integer
Run Code Online (Sandbox Code Playgroud)
好吧,当我看到这一点时,我相当确定这是工作中的单态性限制。众所周知,例如
i = 3
Run Code Online (Sandbox Code Playgroud)
GHCi> :t i
i :: Integer
Run Code Online (Sandbox Code Playgroud)
虽然i :: Num p => p完全有可能。实际上,i :: Num p => p 可以推断出是否-XNoMonomorphismRestriction处于活动状态,即是否禁用了单态性限制。
但是,即使禁用了单态性限制, …
我写了一个类似的函数,Data.Enumerator.List.map它Iteratee与Enumerator一个不同Stream类型的函数兼容.
import Data.Enumerator
test :: Monad m => (ao -> ai) -> Iteratee ai m b -> Iteratee ao m b
test f iter = go $$ iter
where go (Continue k) = continue $
\stream -> go $$ k (fmap f stream)
go (Yield res _) = yield res EOF
Run Code Online (Sandbox Code Playgroud)
如果我省略了类型签名go,这将工作得很好.但是,我想包括它,但我无法确定正确的签名应该是什么.这是我认为它应该是:
go :: Monad m => Step ai m b -> Iteratee ao m b
但这不起作用.
我需要一些关于找到正确类型签名的建议go.
haskell ×7
polymorphism ×4
type-theory ×2
types ×2
enumerator ×1
generics ×1
go ×1
java ×1
javascript ×1
ocaml ×1
oop ×1
recursion ×1
rust ×1
subtyping ×1