English 中文(简体)
对比与Haskell c#泛型参数化类型
原标题:
  • 时间:2009-04-06 07:45:32
  •  标签:

基于一些建议我发现StackOverflow,我挖掘Haskell。我高兴地看到,Haskell年代表现得很像c#泛型参数化类型。两种语言类型参数的建议一个字母(通常)和两种语言似乎遵循类似的过程用一个实际的类型的类型参数。因为,我欣赏这个概念很快。

导致:有哪些方式Haskell年代不同于c#泛型类型参数化的类型?我知道从学习Ruby,您可以进入大麻烦以为你熟悉的概念从一种语言用另一种语言是相同的你的新。通常,问题是更糟的是当功能< em > < / em >非常相似…因为他们通常re < em > < / em > 100%一样的。所以有什么“问题”我可能会咬伤,如果我认为我理解参数化类型基于c#泛型的知识吗?

谢谢。

最佳回答

这里要记住的一个区别:

c#子类型化,但Haskell没有,这意味着,首先,你< em > < / em >知道更多的事情,只要看着Haskell类型。

id :: a -> a

This Haskell function takes a value of a type and returns that same value of that same type. If you give it a Bool, it will return a Bool. Give it a Int, it will return a Int. Give it a Person, it will return a Person.

在c#中,您可以不那么肯定。这是用c#函数:

public T Id<T>(T x);

现在,因为子类型化的你可以叫它像这样:

var pers = Id<Person>(new Student());

而<代码>珀耳斯> < /代码类型的<代码> < /代码>,<代码> Id的参数不是> < /代码功能。事实上<代码>心> < /代码可能有一个更具体的类型不仅仅是<代码> < /代码>的人。<代码> > < /代码的人甚至可以是一个抽象的类型,保证<代码>心> < /代码将有一个更具体的类型。

正如你所看到的,即使有一个函数简单<代码> id > < /代码。net类型系统已经允许更多比严格的类型系统从<代码> Haskell > < /代码。虽然这可能是有用的做一些编程工作,也很难推断程序通过看一个事物的类型(在Haskell是一种乐趣)。


第二件事,有< em > < / em >特别在Haskell多态性(又名重载),通过一个机制称为类型类。

equals :: Eq a => a -> a -> Bool

这个函数检查两个值是否相等。但不是任何两个值,只是有实例的值<代码> Eq > < /代码类。这是有点像限制在c#类型参数:

public bool Equals<T>(T x, T y) where T : IComparable

然而,有一个区别。首先,子类型化:你可以实例化它与<代码> < /代码>,和<代码>学生称之为< /代码>和<代码>教师> < /代码。

但还有一个区别在这编译。c#代码编译几乎说什么其类型。类型检查器确保参数实现适当的接口,和比你好的。

而Haskell代码符合这样的:

equals :: EqDict -> a -> a -> Bool

函数得到一个< em > < / em >额外的参数,一个字典的所有功能需要做<代码> Eq > < /代码的事情。在这里如何使用这个函数,它的编译:

b1 = equals 2 4          --> b1 = equals intEqFunctions 2 4
b2 = equals True False   --> b2 = equals boolEqFunctions True False

这也显示了这种痛苦,让子类型化想象如果这在可能的情况下。

b3 = equals someStudent someTeacher
     --> b3 = equals personEqFunctions someStudent someTeacher

<代码>如何personEqFunctions > < /代码字典应该看看<代码>学生< /代码> = <代码>老师> < /代码?他们甚至不具有相同的字段。

简而言之,在Haskell类型约束一见钟情的样子。net类型约束,实现它们完全不同,编译两个非常不同的事情。

问题回答

我们可以做其他的事情,现在Haskell类型类也。google的“仿制药”Haskell打开高级多态泛型编程领域,超出了标准参数多态性大多数人认为的“仿制药”。

例如,GHC最近获得类型的家庭,使各种各样的有趣的类型编程功能。一个非常简单的例子是每种类型为任意多态数据表示决定容器。

我可以让一个类说、列表

class Listy a where

    data List a 
             -- this allows me to write a specific representation type for every particular  a  I might store!

    empty   :: List a
    cons    :: a -> List a -> List a
    head    :: List a -> a
    tail    :: List a -> List a

我可以写在任何实例化操作的函数列表:

map :: (Listy a, Listy b) => (a -> b) -> List a -> List b
map f as = go as
  where
    go xs
        | null xs   = empty
        | otherwise = f (head xs) `cons` go (tail xs)

但我们从来没有给出特定表示类型。

现在是一个通用的类列表。我可以给特定的狡猾表示基于元素类型。所以例如Int列表,我可以用一个数组:

instance Listy Int where

data List Int = UArray Int Int

...

这样你就可以开始做一些非常强大的泛型编程。

另一大区别是,c#泛型类型构造函数不允许抽象(即类型除了*)而Haskell。试着翻译以下数据类型到c#类:

newtype Fix f = In { out :: f (Fix f) }

跟进的,“你可以进入大麻烦以为你熟悉的概念从一种语言用另一种语言是相同的(你新)”这个问题的一部分:

说,这里s关键的区别(从Ruby)您需要了解当你使用Haskell类类型。给定一个函数等

add :: Num a => a -> a -> a
add x y = x + y

这确实不< em > < / em >意味着<代码> x < /代码>和<代码> y > < /代码都是任何类型的类<代码> Num > < /代码。这意味着x <代码> < /代码>和<代码> y > < /代码是相同的类型,这类型的类<代码> Num > < /代码。“嗯,当然你说;< em > < / em >是一样的< em > < / em >。”我说过,但我花了几个月才停止思考,如果x <代码> < /代码>是<代码> Int y < /代码>和<代码> < /代码>是<代码>整数> < /代码,它就像添加一个<代码> Fixnum < /代码>和<代码> Bignum Ruby > < /代码。而:

*Main> add (2::Int) (3::Integer)

<interactive>:1:14:
    Couldn t match expected type `Int  against inferred type `Integer 
    In the second argument of `add , namely `(3 :: Integer) 
    In the expression: add (2 :: Int) (3 :: Integer)
    In the definition of `it : it = add (2 :: Int) (3 :: Integer)

换句话说,子类化(虽然这两个<代码> Num > < /代码实例的当然也实例<代码> Eq > < /代码)和duck typing消失了,宝贝。

这听起来很简单,很明显,但这需要很长一段时间训练自己本能地明白这一点,而不是在智力上,至少如果你来自多年的Java和Ruby。

不,一旦我习惯了,我不要错过子类化。(好吧,也许一个小,但我已经获得了比我已经输了。当我真的很想念它,我可以试着滥用存在类型。)





相关问题
热门标签