在Haskell中使用递归查找列表中的引用

在Haskell中使用递归查找列表中的引用,haskell,recursion,Haskell,Recursion,我有一个只包含两种元素的列表,Apple和Peach。我需要创建一个函数,给定一个包含这些元素的列表,通过递归返回列表中出现的Apple 以下是我的尝试: 数据水果=苹果|桃 findFruit::[Fruit]->Int findFruit[]=0 findFruit(y:ys) |y==苹果=1+(findFruit ys) |否则=findFruit ys 但它不起作用。我怀疑问题在最后的说明中,但我不能真正理解在哪里,因为我仍然是Haskell的新手 以下是错误日志: Main.hs:

我有一个只包含两种元素的列表,ApplePeach。我需要创建一个函数,给定一个包含这些元素的列表,通过递归返回列表中出现的Apple

以下是我的尝试:

数据水果=苹果|桃
findFruit::[Fruit]->Int
findFruit[]=0
findFruit(y:ys)
|y==苹果=1+(findFruit ys)
|否则=findFruit ys
但它不起作用。我怀疑问题在最后的说明中,但我不能真正理解在哪里,因为我仍然是Haskell的新手

以下是错误日志:

Main.hs:7:8:
    No instance for (Eq Fruit) arising from a use of ‘==’
    In the expression: y == Apple
    In a stmt of a pattern guard for
                   an equation for ‘findFruit’:
      y == Apple
    In an equation for ‘findFruit’:
        findFruit (y : ys)
          | y == Apple = 1 + (findFruit ys)
          | otherwise = findFruit ys
Failed, modules loaded: none.

谢谢你的帮助

您需要向类型构造函数添加
派生Eq
。这样,类型的相等概念将自动实现,并且==运算符将有效使用

data Fruit = Apple | Peach deriving Eq

您的代码还可以,但他不知道如何比较元素,因此,正如编译器告诉您的那样,只需从eq派生:

data Fruit = Apple | Peach deriving (Eq)

这样,编译器就可以比较有关此数据的信息。

您可以保持数据定义不变,并使用模式匹配:

data Fruit = Apple | Peach

findFruit :: [Fruit] -> Int
findFruit []         = 0
findFruit (Apple:ys) = 1 + findFruit ys
findFruit (Peach:ys) = findFruit ys

您可以尝试使用

import Data.Monoid

fruit a _ Apple = a    -- case analysis for Fruit 
fruit _ p Peach = p

countFruit = getSum . mconcat . map (fruit (Sum 1) (Sum 0))

(虽然不是递归的)。

使用模式匹配而不是保护。正如在
findFruit(Apple:xs)=;findFruit(Peach:xs)=……
添加
导出Eq
,正如答案所示,也会起作用,但模式匹配是惯用的,更可取。顺便说一下,如果你调用函数
findFruit
,我会期望一个不同的类型签名,如果你把它作为一个练习,试着实现
countFruit::Fruit->[Fruit]->Int
。如果您想要模块化和概念重用,那么选择
长度要容易得多。过滤器(Apple==)
@gallais必须添加
Eq
约束。如果你想计算所有水果的价格,比如说,我的代码很容易做到这点。i、 e.“易于扩展和修改”。)为什么不
countFruit=sum。地图(水果10)
然后呢?我只是先想到了
mconcat
,而
Sum
是后来的细节。