【问题标题】:Haskell Confusing Type Classes / PolymorphismHaskell 混淆类型类/多态性
【发布时间】:2014-08-10 03:20:55
【问题描述】:

所以基本上我一个月前已经学完了这一部分,我可以做更复杂的事情,但我仍然不明白什么时候在我的类型定义中需要“Ord”或“Eq”等。当我在网上查找它时,出于某种原因让我很困惑。

例如

my_min :: Ord a => a -> a -> a
my_min n1 n2 = if n1<n2 then n1 else n2

为什么需要Ord?你能举一个例子说明你什么时候也需要 Eq(一个非常简单的)?我需要一个非常清晰、基本的解释,说明您何时需要放置这些、要注意什么以及如何尽可能避免使用这些。

通常我只需要像“[Int] -> Int -> [Int]”这样的东西,所以我知道这个函数接受一个整数列表和一个整数,并返回一个整数列表。但是当它包括 Eq 或 Ord 我不知道。

我在关于查找两个列表的讲义中发现这个例子中的这个 Eq 类型是相同的,它是如何应用的?

identical :: Eq a =>[a]->[a]->Bool 
identical [] [] = True 
identical [] _ = False 
identical _ [] = False 
identical (h1:t1) (h2:t2) =
    if h1==h2 
        then (identical t1 t2) 
        else False 

谢谢。

【问题讨论】:

    标签: haskell types polymorphism


    【解决方案1】:

    Ord 表示可以订购该事物,这意味着您可以a 小于(或大于)b。仅使用Eq 就像在说:我知道这两个项目不一样,但我不能说哪个更大或更小。例如,如果您将交通信号灯作为数据类型:

    data TLight = Red | Yellow | Green deriving (Show, Eq)
    
    instance Eq TLight where
      Green == Green = True
      Yellow == Yellow = True
      Red == Red = True
      _ == _ = False
    

    现在我们可以说:Red 不等于Yellow,但我们不能说哪个更大。这就是您不能在 my_min 中使用 TLight 的原因。你不能说哪个更大。

    关于您的第二个问题:“在任何情况下您必须使用EqOrd?”:

    Ord 暗示 Eq。这意味着如果一个类型可以被排序,你也可以检查它是否相等。

    您说您主要处理[Int] -&gt; Int -&gt; [Int],然后您知道它需要一个整数列表和一个整数并返回一个整数。现在,如果您想概括您的函数,您必须问自己:我想在我的函数中使用的可能类型是否需要任何特殊功能?比如它们是否必须能够被排序或等同。

    让我们举几个例子:假设我们要编写一个函数,它接受a 类型的列表和a 类型的元素,并返回带有consed 元素的lisy。它的类型签名会是什么样子?让我们从这个简单的开始:

    consfunc :: [a] -> a -> [a]
    

    我们还需要更多功能吗?不!我们的类型a 可以是任何东西,因为我们不需要它能够被简单地订购,因为这是我们的函数应该做的。

    现在如果我们想要获取一个列表和一个元素并检查该元素是否已经在列表中呢?开头的类型签名是:

    elemfunc :: [a] -> a -> Bool
    

    现在我们的元素必须能够做一些特别的事情吗?是的,我们必须能够检查它是否等于列表中的任何元素,这表明我们的类型a 必须是可等价的,所以我们的类型签名如下所示:

    elemfunc :: (Eq a) => [a] -> a -> Bool
    

    现在如果我们想要获取一个列表和一个元素并在它小于第一个元素时插入它怎么办?你能猜出类型签名的样子吗?

    让我们再次从标准开始,问自己:我们是否需要知道元素和列表必须是同一类型:是的,因为我们的条件需要执行一个测试,要求我们的类型是订购,我们必须在我们的类型签名中包含Ord

    conditionalconsfunc :: (Ord a) => [a] -> a -> [a]
    

    编辑:

    您想查看两个列表是否相同,因此您需要注意两件事:

    您的列表必须包含相同的类型并且列表中的内容必须是平等的,因此Eq

    【讨论】:

    • 好的,我得到了 Ord 部分,在我检查了我的笔记后仍然对 Eq 部分有点不确定,我更新了我的问题以包含示例 - 你所说的 Eq 类型如何适用于该示例函数比较看看 2 个列表是否相同?
    • 惊人的解释,非常感谢!赞成并接受
    【解决方案2】:

    如果您使用像Int 这样的固定类型,则永远不需要类约束。这些只有在使用多态代码时才会出现。

    如果您曾经使用过==/= 函数,或者如果您调用任何其他函数,则需要Eq。 (即,如果您调用的函数在其类型中具有 Eq,那么您的类型也需要具有 Eq。)

    如果您曾经使用过&lt;&gt;compare 或类似功能,则需要Ord。 (再次,或者如果你调用的东西确实如此。)

    请注意,如果您只进行模式匹配,不需要Eq。因此,以下是不同的:

    factorial 1 = 1
    factorial n = n * factorial (n-1)
    -- Only needs Num.
    
    factorial n = if n == 1 then 1 else  n * factorial (n-1)
    -- Needs Num and Eq.
    
    factorial n = if n < 2 then 1 else n * factorial (n-1)
    -- Needs Num, Eq and Ord. (But Ord implies Eq automatically.)
    

    【讨论】:

    • 其实第一个函数也需要Eq。这是因为数字被作为一种特殊情况处理,并且模式匹配被转换为相等测试。尽管如此,您提出的观点是正确的,针对构造函数的模式匹配不需要Eq
    • 我知道它是如何误导我所说的,但我从未说过我只使用 Ints,我只是给出了我通常使用的类型定义的形式,例如“Int -> Int -> Int”或“String -> [String] -> String”,没有 Eqs 和 Ord 是我的观点,所以我问你怎么知道什么时候使用 Ord 和 Eq。但是您的回答也回答了这个问题,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 2016-06-15
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多