【问题标题】:Trying to get my head around (x:xs) and lists?试图了解 (x:xs) 和列表?
【发布时间】:2011-05-03 20:07:48
【问题描述】:

我一直受到列表工作方式的挑战,对整个 (x:xs) 概念感到困惑。我只是似乎没有理解它。

例子

select :: Ord a => a -> [a] -> [a]
select y [] = []
select y (x:xs)
    | x < y     = x : select y xs
    | otherwise = select y xs

附:我确切地知道该函数的作用,但任何人都能够解释这个过程(尤其包括奇怪的Ord a=&gt; 标志)?

任何有效的策略将不胜感激。

提前致谢。伊恩。

【问题讨论】:

    标签: list haskell syntax recursion


    【解决方案1】:

    好的。让我们来看看这里的不同句法元素。

    第 1 行

    select :: Ord a => a -> [a] -> [a]
    

    这是一个类型声明。它是一个函数的声明(因为它有-&gt; 类型)。

    该函数有两个参数。

    • 第一个是任何类型的单个值,用a 表示(小写表示它是多态类型)。
    • 第二个参数是与第一个参数相同的任何类型的列表。

    返回值是任意类型的列表,与参数类型相同。

    Ord a 组件是一个类型类约束,它表示给定此函数的任何类型也必须是 Ord 类的实例。这是一类可以比较的类型。

    第 2 行

    现在我们看第 2 行:

    select y [] = []
    

    这是select 函数本身的一种定义。它非常简单,包含两个参数的模式和结果规范。上面写着:

    如果第一个参数是任何值(我们将其命名为 y),而第二个参数是空列表(由 [] 模式表示),则 select 计算结果为空列表。

    第 3 行

    第 3 行包含列表的另一种情况:

    select y (x:xs)
    

    同样,这是select 函数定义的一部分,用于第二个参数不是空列表的情况。如果它不是一个空列表,那么它是一个带有头部x 和尾部xs 的列表。 “cons”构造函数(:) 结合了列表头和尾。这也是我们对列表进行模式匹配的方式,以提取头部和尾部。

    通过列表头部和尾部的模式匹配,使用(x:xs),我们将一个新变量x绑定到列表头部的值,并将xs绑定到尾部的值列表。

    第 4 行和第 5 行

    最后两行是额外的守卫,如果第二个参数是非空列表,则根据额外的检查进行测试和分支:

    | x < y     = x : select y xs
    | otherwise = select y xs
    

    x 小于第一个参数y 时,第一个守卫触发。如果是这样,我们会返回一个新列表,其中 x 在头部,select 再次应用于尾部。

    如果不是这样,那么我们从列表中删除x,并仅返回递归调用tail时发生的情况。


    有关 Haskell 工作原理的更多信息,我推荐介绍性文本,例如:

    值得你花时间。

    【讨论】:

      【解决方案2】:

      我的 Haskell 充其量是有限的,但我会给出我能给出的答案,以防其他人这样做......

      select :: Ord a => a -> [a] -> [a]
      

      这说:

      选择函数使用任何类型“a”,使得该类型属于类型类“Ord”(Orderable)。它需要一个类型的实例加上一个类型的列表并返回一个列表 类型。

      如果有帮助,在 Java 中这可能表示为 (kindof):

      <T implements Comparable> List<T> select(T value, List<T> listOfValues);
      

      实际的函数定义说:

      • 如果传入一个空列表,则返回一个空列表,否则
      • 如果传入的列表的第一个元素小于该值,则返回一个列表,该列表由附加到列表中的该元素组成,该列表由对应用于列表其余部分的函数求值得到,否则
      • 返回一个由该元素组成的列表,该元素附加到由评估函数产生的列表中(即,没有第一个元素)

      编辑:上述上下文中的可排序意味着“您可以将该类型的值相互比较以确定哪个是'第一个'”。即, 运算符是为类型的值定义的。 “Ord”是由(实际上)Haskell 标准库定义的 TypeClass(Prelude?我忘记它叫什么了)

      【讨论】:

      • 感谢您的回答@RHSeeger。不太确定 Orderable 在编程方面的含义...
      • @maclunian:“这种类型是可订购的”只是你可以比较这种类型的两个东西,例如&lt;.
      • 通常,=> 符号表示约束。其含义是,该类型必须是表示类型类的一个实例(Ord 实现了比较,例如 和
      • 所以另一方面,当您在条件部分使用 == 术语时,只需确认 Eq(即 f :: Eq a => ......)?
      • @maclunian :我相信是这样的,是的。任何属于类型类 Ord 的东西也属于类型类 Eq(因为你需要相等来定义排序),反过来不一定是真的。
      【解决方案3】:

      (x:xs) 用于对 cons 单元格进行模式匹配。当你说[1,2,3] 时,它实际上是1:(2:(3:[])) 的语法糖。因此,当select 1 [1,2,3] 被调用时:

      select y []     = ... -- pattern skipped; [1,2,3] does not match []
      select y (x:xs) = ... -- pattern used, with y = 1, x = 1, and xs = [2,3]
      

      因此,在(x:xs) 中,x 是列表的第一项,xs 是其余项。只有当列表不为空时,此模式才会匹配。

      对于Ord a =&gt; 语法,它的意思是“如果a 是类型类Ord 的一个实例”。 Int 可以在这里工作,因为它有一个 Ord 的实例,看起来像这样:

      instance Ord Int where
          (<=) = primitiveIntLessThanOrEqual
      

      如果你把Ord a 放在外面,只说select :: a -&gt; [a] -&gt; [a],那么x &lt; y 将不起作用,因为它需要Ord 类中的类型参数:

      (<) :: (Ord a) => a -> a -> Bool
      

      【讨论】:

      • 然后它会对其他人做同样的事情,不是吗!
      • @FUZxxl 我想我现在明白了!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-19
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多