当前位置:  开发笔记 > 编程语言 > 正文

将C#泛型与Haskell参数化类型进行对比

如何解决《将C#泛型与Haskell参数化类型进行对比》经验,为你挑选了4个好方法。

根据我在StackOverflow上发现的一些建议,我正在深入研究Haskell.我很高兴看到Haskell的参数化类型与C#泛型非常相似.两种语言都建议使用单个字母作为类型参数(通常),并且两种语言似乎都遵循类似的过程来将实际类型替换为类型参数.因此,我很快就理解了这个概念.

这导致了这一点:Haskell的参数化类型与C#泛型类型的不同之处是什么?我从学习Ruby中了解到,您可能会遇到大麻烦,认为您熟悉的一种语言在您熟悉的另一种语言中是相同的.通常情况下,麻烦更糟糕的是,当功能其实非常相似......因为它们通常不是 100%相同.那么,如果我假设我根据自己对C#泛型的了解理解参数化类型,那么我可能会被一些"陷阱"淹没?

谢谢.



1> Tom Lokhorst..:

请注意以下一个区别:

C#有子类型,但Haskell没有,这意味着,一方面,通过简单地查看Haskell类型就可以了解更多内容.

id :: a -> a

此Haskell函数采用类型的值并返回相同类型的相同值.如果你给它一个Bool,它将返回一个Bool.给它一个Int,它会返回一个Int.给它一个Person,它会返回一个Person.

在C#中,你不能这么肯定.这就是C#中的'功能':

public T Id(T x);

现在,因为子类型,你可以像这样调用它:

var pers = Id(new Student());

虽然pers是类型Person,但Id函数的参数不是.事实上,pers可能有一个更具体的类型而不仅仅是Person.Person甚至可以是抽象类型,保证pers将具有更具体的类型.

正如您所看到的,即使使用像id.NET类型系统这样简单的功能,也已经允许比更严格的类型系统更多的功能Haskell.虽然这对于做一些编程工作可能是有用的,但它也使得通过查看事物的类型(在Haskell中这是一件令人高兴的事情)来推理程序变得更加困难.


第二件事,Haskell中存在ad hoc多态(也称为重载),通过称为"类型类"的机制.

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

此函数检查两个值是否相等.但不仅仅是任何两个值,只是具有Eq该类实例的值.这有点像C#中类型参数的约束:

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

然而,有一点不同.一方面,该分型:你可以用它实例Person,并把它StudentTeacher.

但是,编译的内容也存在差异.C#代码几乎完全符合其类型所说的内容.类型检查器确保参数实现了正确的接口,而不是你的好.

而Haskell代码符合以下内容:

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

该函数获得一个额外的参数,一个包含所有功能的字典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字典应该如何判断a Student是否等于a Teacher?他们甚至没有相同的领域.

简而言之,虽然Haskell类型的限制乍一看可能看起来像.NET类型约束,但它们的实现完全不同,并编译为两个非常不同的东西.



2> Don Stewart..:

我们现在也可以用Haskell类型做其他事情.在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

我可以编写对实例化List的任何东西进行操作的函数:

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

...

所以你可以开始做一些非常强大的通用编程.


当然,在类型族之后,Haskell中存在各种"通用编程"库来进行数据类型泛型编程.原来的提问者要清楚一点:虽然这也被称为"泛型",但这与C#泛型无关.

3> Martijn..:

另一个很大的区别是C#泛型不允许对类型构造函数(即除了*之外的类型)进行抽象,而Haskell则是这样.尝试将以下数据类型转换为C#类:

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



4> Curt J. Samp..:

要跟进,"你可能会遇到大麻烦,认为你用一种语言熟悉的概念在另一种语言[你是新的]中是相同的"这个问题的一部分:

这是使用Haskell类型类时需要了解的关键区别(比如说,Ruby).给定诸如的功能

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

但这并不意味着,xy都是任何类型的类Num.这意味着,xy是完全相同的类型,其类型是类的Num."好吧,当然你说; aa一样." 我也是这样说的,但我花了好几个月的时间才停止思考如果x是一个Int并且y是一个Integer,那就像添加一个FixnumBignumRuby一样.而是:

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

: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)和鸭子打字都没了,宝贝.

这听起来非常简单明了,但是需要花一些时间训练自己本能地理解这一点,而不仅仅是在智力上,至少如果你来自多年的Java和Ruby.

不,一旦我掌握了这一点,我就不会错过子类化.(好吧,也许有点不时,但我获得的收益远远超过我失去的.当我真的很想念它时,我可以尝试滥用存在类型.)

推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有