7

似乎弗雷格关于类型类的想法与 Haskell 有很大不同。尤其是:

  • 语法似乎有所不同,没有明显的原因。

  • 函数类型不能有类实例。(似乎是一个相当奇怪的规则......)

  • 语言规范说明了在子类实例声明中实现超类。(但如果你有钻石继承……这不会是一个错误,但不能保证以某种方式工作?)

  • Frege 对实例的外观不那么挑剔。(类型别名是允许的,类型变量不需要是不同的,等等)

  • 方法可以声明为native,尽管它的含义并不完全清楚。

  • 看来您可以编写type.method访问方法。同样,没有说明这意味着什么或为什么有用。

  • 子类声明可以为超类方法提供默认实现。(?)

简而言之,如果知道这些东西的人可以写一个关于这些东西如何工作的解释,那将会很有用。它在语言规范中列出,但描述有点简洁。

(关于语法:我觉得 Haskell 的实例语法比较合乎逻辑。“如果 X 是 Y 和 Z 的实例,那么它也是 Q 的实例,方式如下……” Haskell 的类语法一直显得有点奇怪对我来说。如果 X 实现Eq了,这并不意味着它实现了Ord,这意味着它可以实现Ord,如果它愿意的话。我不确定一个更好的符号会是什么......)


根据英戈的回答:

  • 我假设为超类方法提供默认实现仅在您“一次性”声明您的实例时才有效?

例如,假设Foo是 的超类Bar。假设每个类都有三个方法(foo1foo2foo3bar1bar2bar3),并Barfoo1. 这应该意味着

实例吧 FB 在哪里
  富二 = ...
  foo3 = ...
  酒吧1 = ...
  酒吧2 = ...
  酒吧3 = ...

应该管用。但这会起作用吗:

实例 Foo FB 在哪里
  富二 = ...
  foo3 = ...

实例吧 FB 在哪里
  酒吧1 = ...
  酒吧2 = ...
  酒吧3 = ...
  • 所以如果我native在类声明中声明一个方法,那只是设置该方法的默认实现?

所以如果我做类似的事情

类 Foobar f 在哪里
  foo :: f -> Int
  本地富

  酒吧 :: f -> 字符串
  本地酒吧

那么这只是意味着如果我为某个 Java 本机类编写一个空实例声明,然后foo映射到object.foo()Java 中?

特别是,如果一个类方法被声明为native,如果我选择,我仍然可以为它提供一些其他实现吗?

  • 每个类型 [constructor] 都是一个命名空间。我知道这对臭名昭著的命名字段问题有什么帮助。我不确定你为什么要在这个命名空间的范围内声明其他东西......
4

1 回答 1

6

您似乎已经非常仔细地阅读了语言规范。伟大的。但是,不,类型类/实例与 Haskell 2010 没有本质区别。只是一点点,那一点是符号。

你的观点:

广告 1. 是的。规则是约束(如果有的话)附加到类型上,类名跟在关键字后面。但是当多参数类型类被添加到语言中时,这将很快改变,有利于 Haskell 语法。

ad 2. 同时全面支持函数类型。这将包含在下一个版本中。不过,当前版本仅支持 (a->b)。

广告 3. 是的。考虑我们的分类类层次结构 Functor -> Applicative -> Monad。您可以只编写以下内容而不是 3 个单独的实例:

instance Monad Foo where
    -- implementation of all methods that are due Monad, Applicative, Functor

广告 4. 是的,目前。但是,多参数类型类将会发生变化。语言规范建议遵守 Haskell 2010 规则。

ad 5. 如果您使用类型类对 Java 类层次结构建模,您将需要它。本机函数声明对于类型类/实例没有什么特别之处。因为你可以在一个类中拥有一个注解和一个默认实现(就像在 Haskell 2010 中一样),你可以以原生声明的形式拥有它,它给出 a)类型和 b)实现(通过引用Java 方法)。

广告 6. 这是正交性。正如你可以在 M 是一个模块的情况下编写 M.foo 一样,你可以在 T 是一个类型(构造函数)时编写 T.foo,因为两者都是命名空间。另外,如果你有“记录”,T.f x当弗雷格无法推断出x.

foo x = x.a + x.b    -- this doesn't work, type of x is unknown
-- remedy 1: provide a type signature
foo :: Record -> Int  -- Record being some data type
-- remedy 2: access the field getter functions directly
foo x = Record.a x + Record.b x

ad 7. 是的,例如,Ord 在比较方面具有 (==) 的默认实现。因此,您可以在不实现 (==) 的情况下创建某事物的 Ord 实例。

希望这可以帮助。一般来说,必须说,语言规范需要 a) 完成和 b) 更新。如果只有一天有36个小时......

此处还讨论了句法问题:https ://groups.google.com/forum/?fromgroups#!topic/frege-programming-language/2mCNWMVg5eY

- - 第二部分 - - - - - -

您的示例将不起作用,因为如果您定义instance Foo FB,则无论其他实例和子类如何,这都必须成立。仅当不存在 Foo 实例时,才会使用 Bar 中的默认 foo1 方法。

那么这只是意味着如果我为某个 Java 原生类编写了一个空实例声明,那么 foo 会映射到 Java 中的 object.foo() 吗?

是的,但它取决于本机声明,它不必是该 java 类的 Java 实例方法,也可以是静态方法或另一个类的方法,或者只是成员访问等。

特别是,如果一个类方法被声明为原生的,如果我选择,我仍然可以为它提供一些其他的实现吗?

当然,就像任何其他默认类方法一样。假设默认类方法是使用模式防护实现的,这并不意味着您必须在实现中使用模式防护。

看,

native [pure] foo "javaspec" :: a -> b -> c

只是意味着:请为我创建一个fooa -> b -> c 类型的 frege 函数,该函数恰好使用javaspec进行实现。(具体应该如何在语言参考的第 6 章中描述。还没有完成。抱歉。)例如:

native pure int2long "(long)" :: Int -> Long

编译器将看到这在语法上是一个强制转换操作,当它看到时:

 ... int2long val ... 

它将生成java代码,如:

((long)(unbox(val))

除此之外,它还将制作一个包装器,以便您可以,例如:

map int2long [1,2,4]

关键是,如果我告诉你:有一个函数 XYz,如果不查看源代码,你将无法判断它是原生函数还是常规函数。因此,native这是将 Java 方法、运算符等提升到 Frege 领域的方法。实际上,在 Haskell 中称为“primOp”的所有内容都只是 Frege 中的本机函数。例如,

pure native + :: Int -> Int -> Int

(当然,这并不总是那么容易。)

每个类型 [constructor] 都是一个命名空间。我知道这对臭名昭著的命名字段问题有什么帮助。我不确定你为什么要在这个命名空间的范围内声明其他东西......

它使您可以对顶级命名空间进行更多控制。除此之外,您不必在那里定义其他内容。一旦我致力于这种简单的方法来解决记录字段问题,我只是没有看到禁止它的理由。

于 2012-05-10T10:29:38.780 回答