Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
If statement 如何在then语句中编写两条语句?_If Statement_Haskell_Tuples - Fatal编程技术网

If statement 如何在then语句中编写两条语句?

If statement 如何在then语句中编写两条语句?,if-statement,haskell,tuples,If Statement,Haskell,Tuples,我正在用Haskell编写一个代码,它获取一个0和1的列表,比如[1,1,0,0,1,0,1],返回一个0和1在类似3,4的列表中出现的数字对 这是我的密码: inc :: Int -> Int inc x = (\x -> x + 1) x count :: [Int] -> (Int,Int) c = (0,0) count x = if null x then c else if head x == 0

我正在用Haskell编写一个代码,它获取一个0和1的列表,比如[1,1,0,0,1,0,1],返回一个0和1在类似3,4的列表中出现的数字对

这是我的密码:

inc :: Int -> Int
inc x = (\x -> x + 1) x

count :: [Int] -> (Int,Int)
c = (0,0)
count x = 
        if null x
            then c
        else if head x == 0
            then do
                inc (fst c)
                count (tail x)
        else if head x == 1
            then do
                inc (snd c) 
                count (tail x)
我也尝试过用一种保护性的方式:

count :: [Int] -> (Int,Int)
c = (0,0)
count x 
          | null x =  c
          | head x == 0 = inc (fst c) >> count (tail x)
          | head x == 1 = inc (snd c) >> count (tail x)

主要的问题是,我不知道如何在一个then语句中实现两个函数。

您必须考虑所有问题。像do{inc fst c;count tail x}这样的东西只有在c是某种可变状态变量时才有意义。Haskell变量是不可变的,所以inc不能修改c的fst,它只能给你一个修改过的副本。如果您将inc改写为完全等效的更简单的形式,这一点可能会更清楚:

inc x = x + 1
事实上,inc=+1也可以

现在,在count中,您试图通过递归循环继续并递增单个累加器变量。可以这样做,但需要明确地将修改后的版本传递给递归调用:

count = go (0,0)
 where go :: (Int,Int) -> [Int] -> (Int,Int)
       go c x
        | null x       = c
        | head x == 0  = go (first inc c) (tail x)
        | head x == 1  = go (second inc c) (tail x)
这种定义小型局部帮助函数go的模式只是一个任意名称,我也可以将其称为getTheCountingDone,并将其用作Haskell中非常常见的函数。基本上是0,0“初始化”c到值0,0,然后开始第一次循环迭代。对于第二次迭代,您递归到例如go first inc c,即使用更新的c变量再次启动循环

我已经使用了递增相应的元组字段。fst只读取第一个字段,即为您提供其值,而第一个字段从元素更新函数生成元组更新函数。代替导入控制。箭头您也可以自己定义:

first :: (a->b) -> (a,y) -> (b,y)
first f (a, y) = (f a, y)
second :: (a->b) -> (x,a) -> (x,b)
second f (x, a) = (x, f a)
实际上,Control.Arrow版本更通用,但您不必担心这一点——您可以用同样的方式使用它

请注意,在Haskell中严重避免使用head和tail解构列表:很容易出错–在访问元素之前,您可能忘记检查列表是否为非空,这将引发严重的运行时错误。更好地使用模式匹配:

事实上,这仍然不安全:你没有详尽的案例;如果列表中不包含0或1,则函数将失败。也许你想计算所有的零和非零元素

count = go (0,0)
 where go c []      = c
       go c (0:xs)  = go (first inc c) xs
       go c (_:xs)  = go (second inc c) xs
另一种选择

> import Data.List(group,sort)
> count = tuplify . map length . group . sort
       where tuplify [x,y] = (x,y)

一个选项是为您的计数函数设置第二个参数,用于跟踪您已计数的内容:

count :: [Int] -> (Int, Int) -> (Int, Int)

-- if the list is empty, return the ones and zeroes already counted
count [] (zeroes, ones) = (zeroes, ones)

-- if first element is a 0, increment the existing count for zeroes
-- and count the rest
count (0:more) (zeroes, ones) = count more (zeroes + 1, ones)

-- as before, but the first element is a 1
count (1:more) (zeroes, ones) = count more (zeroes, ones + 1)
当我们调用count时,我们必须给它一个0,0的“起始计数”:

它返回3,5,因为初始对中的第一个0由列表中的0递增3倍,而初始对中的第二个0由列表中的0递增5倍


此解决方案是一种常见的函数式编程风格,称为“累积参数”。

一种解决方案是对列表进行两次过滤,一次保留0,一次保留1:

count :: [Int] -> (Int, Int)
count nums = (length (filter (0 ==) nums), length (filter (1 ==) nums))

太多的体力劳动。尝试类似计数xs=length$filter==0xs,length$filter==1xs的方法。对不起,我知道我没有真正回答你的问题。inc fst c在排序时不会做任何事情,因为它不会产生副作用。记住,在哈斯凯尔,几乎一切都是不变的。你不能修改c。如果你坚持手工操作,请使用折叠,或者接受@zorans的建议,因为这可能是实现这一点的最简单方法。两种长度都可以。partition==0,其中,与On log n排序相比,f a,b=f a,f b都有On。我不喜欢不必要的分部函数。我会将c参数转换成两个参数,使第一个参数不需要。@USERSFU:我添加了一些解释。不幸的是,对于Bifunctor定律,第一和第二实际上比你的定义所暗示的更懒惰。这是因为他们习惯于打奇怪的箭头结。但这意味着他们在其他情况下会有令人讨厌的潜在表现。结果,我几乎从不使用它们。@dfeuer:知道这一点很好,也很遗憾。你有没有关于为什么这是必要的以及它如何影响性能的参考资料?@leftaroundabout,我没有。我想Edward Kmett告诉我有必要支持ArrowLoop的东西。我怀疑数据。Bifunctor遵循Control.Arrow的语义以避免混淆。至于性能,惰性对肯定会导致空间泄漏,如果严格性分析不消除它们,将导致thunk创建。一般来说,使用第一个f$是可行的!P你只要一直记住它就行了。
count [1,0,1,1,1,0,0,1] (0,0)
count :: [Int] -> (Int, Int)
count nums = (length (filter (0 ==) nums), length (filter (1 ==) nums))