如何在声明中写两个声明?

USE*_*SFU 0 haskell if-statement 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
            then do
                inc (fst c)
                count (tail x)
        else if head x == 1
            then do
                inc (snd c) 
                count (tail x)
Run Code Online (Sandbox Code Playgroud)

我也尝试过这种保护形式:

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)
Run Code Online (Sandbox Code Playgroud)

主要问题是我不确定如何在一个then语句中实现两个函数.

lef*_*out 9

你们正在考虑所有人.喜欢的东西do { inc (fst c); count (tail x) }只会意义,如果c是某种可变状态变量.哈斯克尔变量是不可变的,所以inc不能修改fstc,它只能给你一个修改后的副本.如果您重写inc为完全等效的简单形式,这可能会变得更加清晰:

inc x = x + 1
Run Code Online (Sandbox Code Playgroud)

(事实上​​,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)
Run Code Online (Sandbox Code Playgroud)

这种定义一个小的本地辅助函数的模式(go只是一个任意的名称,我也可以称之为getTheCountingDone),并将它用作递归"循环体"在Haskell中非常常见.基本上go (0,0)"初始化" c到值(0,0),然后开始第一次循环迭代.对于第二次迭代,您可以递归到例如go (first inc c),即使用更新的c变量再次启动循环.

我已经使用firstsecond增加了相应的元组字段.fst读取第一个字段,即给出它的值,而first从元素更新函数创建一个元组更新函数.而不是import Control.Arrow你也可以自己定义:

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)
Run Code Online (Sandbox Code Playgroud)

(该Control.Arrow版本实际上更通用,但您不必担心 - 您可以以相同的方式使用它.)

请注意,在Haskell 中解析列表head并且tail在Haskell中被大量避开:它很容易出错 - 在访问元素之前,您可能忘记检查列表是否为非空,这将引发令人讨厌的运行时错误.更好地使用模式匹配:

count = go (0,0)
 where go c []      = c
       go c (0:xs)  = go (first inc c) xs
       go c (1:xs)  = go (second inc c) xs
Run Code Online (Sandbox Code Playgroud)

实际上这仍然不安全:你没有详尽的案件; 如果列表包含除零或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
Run Code Online (Sandbox Code Playgroud)