在Haskell中实现无输入变量的递归

在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

所以我对编程还是很陌生,我对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 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
是保留的语法关键字)。最近,我个人开始使用just
g

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