什么时候使用类型类?

时间:2013-11-19 09:58:49

标签: haskell

通常当我创建函数时,我不知道哪些函数最好使用类型类(EqIntegral等),因为有时候不需要像以下那样使用它们: / p>

factorial :: Int -> Int 
bla bla bla 
bla bla bla

factorial :: (Integral a) => a -> a
bla bla bla
bla bla bla

我相信第二个只是花时间和地点 但是在elem函数中,写Eqelleme下面是elem

非常重要
elemme :: Eq a => a -> [a] -> Bool
y `elemme` [] = False
y `elemme` (x:xs) = if y == x then True else y `elemme` xs 

请告诉我一些事情。感谢。

2 个答案:

答案 0 :(得分:9)

类型类可以让你编写更多通用函数。 Haskell有很棒的工具可以让你指定一个函数适用于所有类型,比如

id :: a -> a
id a = a

但有些事情并不适用于所有类型,

(==) :: Eq a => a -> a -> Bool

如果没有类型类,我们要么必须为每种类型写一个新的==

eqInteger :: Integer -> Integer -> Bool

或者指定所有类型都是等同的,并且可以测试是否相等。但是你可以问一下

id == const 1

因此,当您发现自己想要指定您的函数在所有类型的子集上工作时,请转到类型类。

我经常喜欢编写这些更通用的函数,即使我不使用它们超过一种类型,因为签名越一般,实现的选项就越少,这使我更容易知道我没有'做了一些愚蠢的事情

id :: Integer -> Integer
id = (+1)

你基本上声明你的函数只需要X函数,这样就可以使用错误的函数来获得编译器错误。

答案 1 :(得分:4)

我使我的功能尽可能通用的一个好处是,它通常允许我以前没有想到的用例。当你开始制作一般的东西时,你开始为你的功能提出奇怪的用途。

你去,“但如果这个值是一个函数怎么办?”或者“如果我允许这个任何仿函数怎么办?其他仿函数会有什么结果?它有用吗?”事实证明,很多情况下它 !在我看来,这是Haskell如此伟大的原因之一。很容易“意外”创建非常可重用的功能。

在其他语言中,您可以为特定目的设计功能并以这种方式使用它们。在Haskell中,您为特定目的设计函数并为它们提供一般类型签名,并且突然它们适用于您未设计它们的大量案例。


@jozefg对限制可能实现的一般性提出了一个很好的观点。我只想更多地关注聚光灯,因为它实际上是一个非常强大的概念。通过一些通用函数,您实际上可以完全确定函数仅基于类型签名执行的操作,因为该通用签名只有一种可能的实现。

我最近遇到了签名

mystery :: (a -> b -> c) -> (a -> b) -> a -> c

这很有趣,因为我们实际上可以根据它的作用找出它的功能。我们有

mystery :: (a -> b -> c) -> (a -> b) -> a -> c
mystery    f                g           x = ...

我们需要它返回某种c值。我们获得c类型值的唯一方法是将函数f应用于a值和b值。我们已经有一个a值 - 这是x参数。我们可以部分应用f x :: b -> c,但我们仍然需要b值来获取我们想要的c值。

当然,解决方案是应用g x来获取b值,然后我们可以将其粘贴到f中,从而最终返回c值。对此的描述有点复杂,但是如果你在头脑中解决这个问题,你就会到达

mystery f g x = f x (g x)

执行与库函数ap相同的操作。 (来自Control.Applicative。)

非常酷,你可以根据它的类型签名找出一个函数的功能!