在Haskell中实现无输入变量的递归
所以我对编程还是很陌生,我对Haskell的语法也很费劲。我知道我想要实现什么,但我不确定如何实现,所以我来这里问 所以我得到的是一堆没有特定顺序的数字,由3个不同的函数定义。例如:在Haskell中实现无输入变量的递归,haskell,recursion,Haskell,Recursion,所以我对编程还是很陌生,我对Haskell的语法也很费劲。我知道我想要实现什么,但我不确定如何实现,所以我来这里问 所以我得到的是一堆没有特定顺序的数字,由3个不同的函数定义。例如: lowestnumber = 4 highestnumber 5 = True highestnumber _ = False above 4 = 11 above 11 = 18 above 18 = 2 above 2 = 3 above 3 = 5 above 5 = error "highest Nu
lowestnumber = 4
highestnumber 5 = True
highestnumber _ = False
above 4 = 11
above 11 = 18
above 18 = 2
above 2 = 3
above 3 = 5
above 5 = error "highest Number"
above _ = error "Not part of the pile"
现在,我想写一个函数,检查某个数字是否是这个堆的一部分,以及一个不同的函数“sum'=”,它对列表中的所有元素求和,而不使用输入变量。首先,我通过定义一个列表并使用listcommands来解决这些问题,以便总结并查看某个内容是否是该列表中的“elem
”,但我应该在不使用列表的情况下解决它
所以我有办法解决这个问题,但我不知道如何在没有收到无数错误的情况下编写它。
我尝试使用check函数的一些示例:
check x = if above x /= error "Not part of the stack" || lowestnumber == x then True else False
我也试过这样用“u”进行检查,但也不起作用:
check x if above x == _ || lowestnumber == x then True else False
我对求和函数的想法是:
sum' = lowestnumber + above lowestnumber + above (above lowestnumber) + above (above (above lowestnumber))
或者类似的
sum' = lowestnumber + (above sum')
elements = takeUntil highestnumber (iterate above lowestnumber)
takeUntil p xs = foldr (\x r -> if p x then [x] else x:r) [] xs
我明白了
以此类推,但我没有弄清楚如何使用递归来实现这一点,这显然是一种可行的方法
希望这个问题不是太愚蠢!我希望你能帮助我:)
编辑:好的,这是我的3个函数问题的解决方案
sumup' a b
|highestNumber a == True = a+b
|otherwise = sumup' (above a) (a+b)
sumup = sumup' lowestNumber 0
check' a b
|a == b = True
|True == highestNumber a && a==b = True
|True == highestNumber a && a/=b = False
|check' (above a) (b) == True = True
|otherwise = False
check b = check' (lowestNumber) (b)
above' :: Integer -> Integer -> Bool
above' x y
| check x == False = False
| check y == False = False
| highestNumber y == True = False
| highestNumber x == True = True
| x==y = True
| above' x (above y) == True = True
| otherwise = False
首先,我通过定义一个列表并使用
列出命令,以总结并查看是否有“元素”
但是我应该不用列表来解决它
您可以通过展开elem来解决此问题,如下所示:
x `elem` [1,2,3]
与
x == 1 || x == 2 || x == 3
当你在做的时候
sum' = 4 + 11 + 18 + 2 + 4 + 5
您还可以使用以下内容构建所有元素的列表
sum' = lowestnumber + (above sum')
elements = takeUntil highestnumber (iterate above lowestnumber)
takeUntil p xs = foldr (\x r -> if p x then [x] else x:r) [] xs
这是唯一一种不用常数就可以编写check和sum函数的方法
我们不能使用
takeWhile(不是.highestnumber)
,因为我们会错过最高的数字。因此,takeUntil
必须以这种方式定义,以便在其输出中包含中断元素。您应该在没有列表的情况下执行此操作,这很遗憾,因为这将是非常惯用的解决方案
下一个最惯用的方法是一些通用的方法,可以遍历你的堆。您基本上需要对数字进行折叠:
foldlMyPile :: (a -> Int -> a) -> a -> {- Pile -> -} a
foldlMyPile f = go lowestNumber
where go n accum
| highestNumber n = result
| otherwise = go (above n) result
where result = f accum n
一旦你有了这个,你就可以用它来定义和、元素等等
如果您想在没有列表的情况下完成此操作,请保持一个运行总数,并使用递归 如果你是
最高的数字
,只需将其添加到当前总数中并停止,
否则,将该数字添加到您的总数total+n
,然后转到n上面的下一个:
add n total |highestnumber n = total + n
|otherwise = add (above n) (total + n)
那你就可以了
answer = add lowestnumber 0
Haskell中的各种高阶函数捕获各种递归(和corecursion†)模式,如迭代
,foldr
,展开
等
这里我们可以使用,其中直到pfx
产生迭代应用f
直到p
保持的结果,从x
开始:
sumPile = snd $
until (highestnumber . fst)
(\(a,b)->(above a, b + above a))
(lowestnumber, lowestnumber)
而且
inThePile p = p==until (\n-> highestnumber n || n==p) above lowestnumber
†基本上,使用累加器进行递归,在从起始情况开始的过程中构建其结果,而常规递归在从基本情况返回的过程中构建其结果。关于您的三个新函数。
这几乎和安德烈的回答一模一样。它很好,除了==Temp
是完全多余的,不需要summap'
通常也是一个内部函数,移动到where
子句中。因此,它不必具有描述性名称。有些使用(受方案启发的?循环
),有些使用go
(因为do
是保留的语法关键字)。最近,我个人开始使用justg
:
sumup = g lowestNumber 0 -- sum up all numbers in the pile
where
g n tot -- short, descriptive/suggestive var names
| highestNumber n = n + tot
| otherwise = g (above n) (n + tot)
这通常写为
check' a b = (a == b) ||
(highestNumber a && a==b) ||
( not (highestNumber a && a/=b)
&& check' (above a) b )
在第二个测试中,如果a==b
为真,那么它在第一个规则中已经起作用了,因此我们可以假设a/=b
。所以第二次测试总是错误的;我们得到了
check' a b = (a == b) ||
(not (highestNumber a) && check' (above a) b)
看起来还不错。它也可以写与警卫再次,如图所示
check' a b | (a == b) = True
| highestNumber a = False
| otherwise = check' (above a) b
或者,为了保持一致性,使用简短的提示性变量名和交换的参数顺序
check' n i | highestNumber i = i == n
| otherwise = i == n || check' n (above i)
这与第一个
总结代码的结构非常相似
现在是第三个函数。首先,它也可以用
check'
轻松定义,只需从给定的低数字开始,而不是从最低的数字开始:
higher top low = check low && not (highestNumber low)
&& check' top (above low)
(“更高”是一个更独特的名字,是吗?)。您的版本:
higher :: Integer -> Integer -> Bool
higher x y
| check x == False = False -- not(check x == False) -- ==
| check y == False = False -- check x == True -- ==
| highestNumber y == True = False -- check x
| highestNumber x == True = True
| x==y = True
| higher x (above y) == True = True
| otherwise = False
再次,简化,
higher x y = check x && check y
&& not (highestNumber y)
&& ( highestNumber x
|| x==y -- really?
|| higher x (above y) ) -- too strong
因此,这本书似乎有问题。首先,我建议您阅读一本关于haskell的正确教程,比如说,它是免费的!更重要的是,
error
与您尝试使用它的方式不一样。一般情况下应该避免,你最好研究一下也许
。我一直在读《向你学习哈斯克尔》,我在那里找不到我问题的答案,但我可能只是做得不够!谢谢anwyways,我会调查一下MaybeCan,你是用命令式语言写的吗?如果你能比较一下,可能更容易理解。把它贴上去,我会试着用haskell翻译。我不能。Haskell是我学习的第一语言。好的,把你的完整代码贴在上面,这样我们就有了一个更好的图片。另外,我建议你在haskell irc呆上一段时间,在你尝试的时候直接问一些小问题。谢谢!这很好用,我现在会尝试自己重新制作。啊,我现在是一只快乐的小狗!我能够重新创建您的函数,并按照您的示例创建了check函数。我想这真的帮助我理解了递归!谢谢。遗憾的是,我似乎无法将我的checkfunction复制到评论中,但它看起来很糟糕:D@user2299050:你也可以把你的答案写下来作为答案@yatima2975哈,是的,我想我会这么做的相反,它并不存在
higher x y = check x && check y
&& not (highestNumber y)
&& ( highestNumber x
|| x==y -- really?
|| higher x (above y) ) -- too strong