有关LYAH实施取假的问题

时间:2018-07-16 16:28:42

标签: haskell

我一直在尝试通过学习《 haskell》这本书来学习haskell。本书通过以下方式介绍了take的实现:

take' :: (Num i, Ord i) => i -> [a] -> [a]  
take' n _  
    | n <= 0   = []  
take' _ []     = []  
take' n (x:xs) = x : take' (n-1) xs  

对此代码我有两个问题:

  1. 为什么在函数声明中我们使用相同的字母i来声明(Num i, Ord i)

  2. 这是否不会覆盖iNum类型而iOrd类型的事实?

  3. 我想修改take',以便如果n大于列表的长度,则会显示一条消息。我尝试通过在take的定义中使用函数长度来实现此目的,但随后该函数无法加载:

    take'n _

        | n > length _ = print "n greater than length of list"
    

3 个答案:

答案 0 :(得分:5)

  

为什么在函数声明中我们使用相同的字母i进行声明(数字i,奥德i)?

这是否不覆盖i属于Num且i属于Ord的事实?

这不是类型声明,而是类型 constraint 。这意味着“ i是既是数字又是可排序的某种类型”(您可以使用不可排序的数字和可不是数字的可排序事物)。

  

| n>长度_ =打印“ n大于列表的长度”

这不起作用,因为_是通配符模式-list参数实际上没有绑定任何东西。用模式写_意味着“我知道应该去那里,但是我不在乎它是什么”。如果要使用列表,则必须为其命名。

(提示:您不需要计算列表的长度-在另一种情况下,您可以检查调用方是否尝试从列表中取出比预期多的元素)

(提示2:print "n greater than length of list"在这里不起作用,因为它的类型为IO ()而不是[a]-请记住,该函数仍需要返回正确的类型!输入无效,并且要打印错误消息并终止程序,可以使用error函数。)

答案 1 :(得分:1)

  
      
  1. 为什么在函数声明中我们使用相同的字母i来声明(Num i, Ord i)
  2. 这是否不会覆盖iNum类型而iOrd类型的事实吗?   

首先,让我们指出主要的误解。 Num不是类型。 Ord不是类型。因此,i不能具有类型NumOrd

相反,i代表一般的未知类型,将在调用take'时确定。在通话时,i可以是IntIntegerFloat,仅举几例。

原则上,呼叫者可以选择他们想要的任何类型。但是,约束(Num i, Ord i)意味着调用方必须选择满足i(即它是数字类型)和Num i(即它也是数字类型)的类型Ord i。有序类型)。这两个约束条件是相辅相成的:复杂的数字是数字,但不是有序的;布尔类型是有序的,但不是数字的。

因此,这些约束之间没有矛盾。

答案 2 :(得分:1)

  

为什么在函数声明中我们使用相同的字母i来声明(Num i, Ord i)

这是否不会覆盖我的Num类型为i类型为Ord的事实?

这是类型约束。这意味着类型i需要提供Num(或Ord)类型类定义的功能。如果您编写具有相同类型的多个类型类(此处为i),则意味着i必须是所有这些类型类的实例(并实现两个类型类都声明的功能)。对于此特定示例,这意味着i必须是(<=) :: Ord i => i -> i -> i(-) :: Num i => i -> i -> i存在的类型。如果您省略两者之一,则无法再评估n <= 0n-1,因为不再保证这些函数存在。

  

我要修改take',以便如果n大于列表的长度,则会显示一条消息。我试图通过在take的定义中使用函数长度来实现此目的,但是函数无法加载。

Haskell的想法是printIO ()。如果您写print,您将打印。这基本上意味着您已经{em>封装了这个IO动作。因此,您可以将其传递出去,例如在main中使用它来实际打印一些内容。但是,它与输出类型[a]冲突。但是,您可以在此处使用trace作为某种调试来执行不安全 IO操作。对于营地:

import Debug.Trace

take' :: (Num i, Ord i) => i -> [a] -> [a]  
take' n _  
    | n <= 0   = []  
take' n [] | n > 0 = trace "n greater than length of list" []
           | otherwise = []  
take' n (x:xs) = x : take' (n-1) xs

但这用于调试的目的。 Haskell的想法是使用声明性语言。结果,您指定要返回的 ,希望发生的 方式不多,需要采取哪些措施。