繁体   English   中英

与Haskell中的(高阶)函数进行模式匹配

[英]Pattern-matching with (higher-order) functions in Haskell

我正在尝试使用在线书“学习你的哈斯克尔”学习一些Haskell,我对高阶函数有疑问。

我看了一些例子 ,我想做一些更高级的功能,但我不知道为什么我总是阅读以下异常:

***例外:euler13.hs:(11,0) - (15,39):函数中的非详尽模式适用

我定义的功能就是这个:

apply :: (Num b, Ord b) => (a -> a) -> b -> [a] -> [a]
apply f n [] = []
apply f n [x]
    | n <= 1    = map f [x]
    | otherwise = apply f (n-1) (map f [x])

我想将一个名为'f'的具体函数'n'应用于列表'[x]'。 我试图使这个函数具有多态性,因此param的类型是'a'。 但我也想使用数字和列表,所以我直接使用一个列表(如果我只想使用该函数的数字,那么显然会是[数字])

请问有人帮帮我吗? 我喜欢这种语言,但是当你学习它时有点困难,因为它与Java或c有很大不同(例如)

谢谢!

删除x周围的[] 否则,第二个模式只能匹配仅包含1个元素的列表。

apply f n x
    | n <= 1    = map f x
    | otherwise = apply f (n-1) (map f x)

这与其他人所说的没有什么不同,但也许这一点应该付出代价? 列表有两个基本的“构造函数”,因此在从列表定义函数时需要考虑两个基本情况:形式[](:) 后者, (:)可以加入任何具有该类事物列表的东西,因此1[] - 1:[][1] 或者它可以加入1与这种类型的东西: 1:(1:[])1:[1] ,即[1,1]作为特殊语法让我们写。

如果您自己定义了列表,那么更明显的是会出现什么问题,写道:

data List a = Nil | Cons a (List a) deriving (Show, Eq, Ord)

使用[]x:xs就像这样的东西。 类似地,特殊的String糖让我们写"abc"而不是['a','b','c'] ,这比'a':'b':'c':[]更好'a':'b':'c':[] (根据上面的定义,我们必须编写Cons 'a' (Cons 'b' (Cons 'c' Nil)))这对于短字符串来说有点多了! - 虽然它也说明为什么人们应该更喜欢ByteString和字符串的Text表示用于许多目的。)有了这样一个更详细的列表定义,我们需要添加我们自己的map (或者更确切地说是fmap ),所以我们可以说

instance Functor List where 
   fmap f Nil = Nil
   fmap f (Cons first rest) = Cons (f first) (fmap f rest)

请注意,在为这种情况定义fmap ,我必须考虑我的List类型的两种类型的构造函数, NilCons first rest (或者经常编写的Cons x xs )。

或许你还没有完成对LYAH中Functor类型类的一般性讨论 - 在这种情况下,只要考虑你可以将自己的map定义为

listMap f Nil = Nil
listMap f (Cons first rest) = Cons (f first) (listMap f rest)

在任何情况下,鉴于这种对列表类型的重写,您的实际函数定义将是:

apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a
apply f n Nil = Nil
apply f n (Cons first Nil)
    | n <= 1    = fmap f (Cons first Nil)  -- or listMap f (Cons first Nil)
    | otherwise = apply f (n-1) (fmap f (Cons first Nil))

您涉及的案例包括:

apply f n Nil 
apply f n (Cons first Nil)

Cons first Nilfirst : []相同first : [][first] - 即你写的时候是[x] 但这意味着你没有涵盖所有案例,你的定义是“非详尽的”。 如果它有多个成员,你还没有说过如何将fn应用于列表。 如果列表的形式为Cons x (Cons y Nil)Cons x (Cons y (Cons z Nil))而不是Nil (您的第一行)或Cons x Nil (您的第二行),该怎么办?

解决方案正如其他人所说,或使用我们的desugared列表类型:

apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a
apply f n Nil = Nil
apply f n (Cons first rest)
    | n <= 1    = fmap f (Cons first rest)
    | otherwise = apply f (n-1) (fmap f (Cons first rest))

这里的“变量” rest涵盖了所有的名单, Nil与否。 因此我们得到:

*Main> apply (+1) 3 Nil
Nil
*Main> apply (+1) 3 (Cons 3 Nil)
Cons 6 Nil

像你一样,但也:

*Main> apply (+1) 3 (Cons 0 (Cons 1 (Cons 2 Nil)))
Cons 3 (Cons 4 (Cons 5 Nil))

您可以定义apply于两种情况:n和一个空表n和一个元素的列表。 当列表包含多个元素时会发生什么? 这是缺失的模式。

与其他人相比,这不是一个新的答案,但希望是有见地的。

您已经在函数定义中展示了对模式匹配的一些理解; 当第一个模式无法匹配时,评估将继续进行到下一个模式。 能够无法匹配的模式被视为“可反复”。

通常,最后一个函数定义是“无可辩驳的”,这意味着它始终匹配是个好主意。 来自Haskell 2010报告

无可辩驳的模式如下:变量,通配符,N apat,其中N是由newtype定义的构造函数,apat是无可辩驳的,var @ apat,其中apat是无可辩驳的,或者是~apat形式。 所有其他模式都是可以反驳的。

你的误解是你认为[x]是一个变量(无可辩驳的模式),当它实际上是一个可反射的模式(单个元素列表的模式,它将x绑定到那个单个元素)。

假设您编写的函数仅适用于长度为3的列表。如果您需要比“非详尽模式”更具描述性的错误消息,则可以使用通配符(下划线)无可辩驳的模式。 一个简单的例子:

sum3 [x,y,z] = x+y+z
sum3 _       = error "sum3 only works on lists of length 3"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM