带case表达式的递归Haskell
考虑以下代码,其中函数带case表达式的递归Haskell,haskell,Haskell,考虑以下代码,其中函数sumFood采用 列出Food的xs,并返回一个整数元组。在这个元组中,第一个整数表示xs中包含的水果数量,第二个整数表示蔬菜数量 module Apples where data Food = Apple | Orange | Carrot | Potato deriving(Show) sumFood :: [Food] -> (Int, Int) sumFood (x:xs) = let v=0 f=0
sumFood
采用
列出Food
的xs
,并返回一个整数元组。在这个元组中,第一个整数表示xs
中包含的水果数量,第二个整数表示蔬菜数量
module Apples where
data Food = Apple | Orange | Carrot | Potato deriving(Show)
sumFood :: [Food] -> (Int, Int)
sumFood (x:xs) = let v=0
f=0 in if ((length xs)-1) > 0 then
case x of Apple -> (f + 1, v)
Orange -> (f + 1, v)
Carrot -> (f, v + 1)
Potato -> (f, v + 1)
else sumFood xs
但是如果我输入sumFood[Apple,Orange]
或[Apple,Apple]
它将返回(0,0),答案应该是(2,0)
实现必须使用大小写表达式
也许一个提示会有用。实际上,您已经获得了大部分正确的位和片段,但顺序错误-并且您忘记了对递归的结果执行任何操作 您可以替换
f
和v
的值,然后查看发生了什么:
sumFood (x:xs) = let v = 0
f = 0 in
if ((length xs)-1) > 0 then
case x of Apple -> (f + 1, v)
Orange -> (f + 1, v)
Carrot -> (f, v + 1)
Potato -> (f, v + 1)
else sumFood xs
变成
sumFood (x:xs) =
if ((length xs)-1) > 0 then
case x of Apple -> (0 + 1, 0)
Orange -> (0 + 1, 0)
Carrot -> (0, 0 + 1)
Potato -> (0, 0 + 1)
else sumFood xs
现在,((length xs)-1)>0
是length xs>1
,这意味着length(x:xs)>2
,所以实际上
- 如果列表包含两个以上的元素,则结果为
或(1,0)
(0,1)
- 否则,将递归
(1,0)
或(0,1)
——除非输入少于三个元素,否则最终会遇到模式匹配失败
主要问题是,您从未使用递归的结果,因此结果始终是基本情况的结果
首先,一条有用的经验法则是永远不要使用长度
;在列表结构上使用模式匹配
从基本情况开始:空列表既不包含水果也不包含蔬菜
sumFood [] = (0,0)
接下来,您需要从递归中获取结果,然后将其添加到结果的适当元素中:
sumFood (x:xs) = let (f, v) = sumFood xs
in
case x of Apple -> (f + 1, v)
...
(,)
的Bifunctor
实例使这变得容易;它允许您使用第一个
和第二个
将(+1)
应用于元组的适当元素,这允许您简单地将列表折叠成元组
import Data.Bifunctor
sumFood :: [Food] -> (Int, Int)
sumFood = foldr foo (0,0)
where foo Apple = first (+1)
foo Orange = first (+1)
foo Carrot = second (+1)
foo Potato = second (+1)
如果需要使用case
表达式,请注意,定义一个函数的多个方程只是其中一个的语法糖:
sumFood :: [Food] -> (Int, Int)
sumFood = foldr foo (0,0)
where foo food = case food of
Apple -> first (+1)
Orange -> first (+1)
Carrot -> second (+1)
Potato -> second (+1)
如果您也不允许使用Bifunctor
,那么您可以很容易地动态实现自己:
sumFood :: [Food] -> (Int, Int)
sumFood = foldr foo (0,0)
where foo food = case food of
Apple -> \(f,v) -> (f+1,v)
Orange -> \(f,v) -> (f+1,v)
Carrot -> \(f,v) -> (f,v+1)
Potato -> \(f,v) -> (f,v+1)
您的实现只匹配具有一个元素的列表。。。看一看我知道这就是为什么我在这里问我知道递归,我试图使用它,但与大小写表达式!!!很难,你是不是在问如何匹配列表?这与递归无关。我的问题是,如果我键入[Apple,Orange,Apple]=>我将得到(3,0),我想我需要递归,我不知道!!!所以在递归的每个步骤中,您都会有一个列表,其中少了一个元素。。。最后是一张空名单。你最好考虑一下。此外,在
case
中,您将检查当前元素而不是列表,如苹果的case x->…
等更合适。