简体   繁体   English

什么是Java的奇怪重复通用模式的Haskell等价物?

[英]What is the Haskell equivalent of Java's Curiously Recurring Generic Pattern?

A question just came up about java generics. 关于java泛型的问题刚刚出现。 The example code is: 示例代码是:

public interface A < T extends A < T> > {

}  

A linked question asks about 一个链接的问题询问

Class Enum<E extends Enum<E>> ...

When I try to read the java documentation about these kinds of generic expressions, my eyes glaze over and it's Greek to me. 当我尝试阅读关于这些通用表达式的java文档时,我的眼睛茫然,这对我来说是希腊语。

I'm hoping that I can understand them in terms of the Haskell equivalent! 我希望我可以用Haskell等价物来理解它们!

What is the equivalent (or similar) in Haskell of one or both of these examples? Haskell中这些例子中的一个或两个的等价(或类似)是什么?

This trick is used to allow the interface to refer to the concrete implementation type, for example to enforce that the type of the argument and the type of the result are the same type as the implementing class in something like this: 这个技巧用于允许接口引用具体的实现类型,例如强制参数的类型和结果的类型与实现类的类型相同,如下所示:

public interface Num<A extends Num<A>> {
    A add(A other); 
}

This is similar to what you get for free with type classes in Haskell: 这与您在Haskell中使用类型类免费获得的类似:

class Num a where
    (+) :: a -> a -> a

This is interesting, as this has perplexed me also. 这很有趣,因为这也困扰了我。 Let's try to model it. 我们试着去模拟它。 I will probably not end up with the same thing this idiom is used for in Java. 我可能不会在Java中使用这个习惯用法。

If a type A inherits from a type B , in functional land that means that there is a function B -> A . 如果类型A继承自类型B ,则在功能区域中意味着存在函数B -> A Do not worry about the difference between classes and interfaces at this point; 此时不要担心类和接口之间的区别; there is little difference in the functional translation (an interface is just a record of functions). 功能翻译几乎没有区别(界面只是功能记录)。 Let's do a non-recursive translation to get a feel for it: 让我们做一个非递归的翻译来感受它:

interface Showable {
    string show();
}

interface Describer<T extends Showable> { }

Translating to records of functions: 转换为功能记录:

data Showable = Showable { show :: String }

data Describer t = Describer { showable :: t -> Showable }

If we forget about downcasting, then if we have some object in Java such that all we know about it is that it is a Showable , then it corresponds to having a Showable object in Haskell. 如果我们忘记了向下转换,那么如果我们在Java中有一些对象,我们所知道的就是它是一个Showable ,那么它对应于在Haskell中有一个Showable对象。 On the surface, passing a Showable and passing a string feel like different things, but they are equivalent. 表面上,传递一个Showable并传递一个string就像是不同的东西,但它们是等价的。

The extends Showable constraint enters in that if we have a Describer t then we know that t "is" Showable ; extends Showable约束进入,如果我们有一个Describer t Showable Describer t那么我们知道t “是”可Showable ; ie there exists a function t -> Showable . 即存在函数t -> Showable

makeDescriber :: (t -> Showable) -> Describer t
makeDescriber f = Describer { showable = f }

Now let's go to hammar's exmaple, incorporating polymorphism. 现在让我们来看看hammar的exmaple,结合多态性。

interface Number<A extends Number<A>> {
    A add(A other); 
}

translating to a record of functions 转换为功能记录

data Number a = Number {
    add :: a -> a,
    number :: a -> Number a
}

So now if we have a Number a , then we know that a "is" a Number a ; 因此,如果我们有一个Number a ,那么我们就知道a “是”一个Number a ; ie there is a function a -> Number a . 即有一个函数a -> Number a

Instances of the java interface Number become functions on a type. java接口的实例Number成为一个类型的函数。

intNumber :: Integer -> Number Integer
intNumber x = Number { add = \y -> x + y, number = intNumber }

This function corresponds to a class Integer extends Number<Integer> . 此函数对应于class Integer extends Number<Integer> If we have two integers x and y , we can add them using this "OO" style: 如果我们有两个整数xy ,我们可以使用这个“OO”样式添加它们:

z :: Integer -> Integer -> Integer
z x y = intNumber x `add` y

And what about the generic function: 通用功能怎么样:

T Add< T extends Number<T> >(T x, T y) { return x.add(y); }

(hmm is that correct Java syntax? My experience of this style is from C#) (嗯是正确的Java语法?我对这种风格的体验来自C#)

Remember the constraints become functions, so: 记住约束成为函数,所以:

add' :: (t -> Number t) -> t -> t -> t
add' n x y = n x `add` y

Of course, in Haskell, we see how bundling an object together with the operations it supports is kind of convoluted, so we prefer to separate them: 当然,在Haskell中,我们看到将对象与它支持的操作捆绑在一起是多么复杂,所以我们更喜欢将它们分开:

data Num t = Num { add :: t -> t -> t }

add' :: Num t -> t -> t -> t
add' n x y = add n x y

And we instantiate the Num dictionary with the actual operations, eg. 我们用实际操作实例化Num字典,例如。

integerNum :: Num Integer
integerNum = Num { add = (+) }

Typeclasses are just a bit of syntactic sugar over this latter idea. 对于后一种想法,类型类只是一些语法糖。

Maybe that helps? 也许这有帮助吗? I just wanted to see how it would translate literally. 我只是想看看它是如何翻译的。

I don't know if there is an equivalent statement for Haskell, but Haskell does have typeclasses . 我不知道Haskell是否有相同的语句,但Haskell确实有类型类 For example, Show is a typeclass, and many objects "extend" or "implement" show, that is, you can "show 3", "show [1,2,3,4]", etc. 例如,Show是一个类型类,许多对象“扩展”或“实现”显示,也就是说,你可以“显示3”,“显示[1,2,3,4]”等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM