【问题标题】:How to calculate the occurrences of Char in an ordered [Char]?如何计算有序 [Char] 中 Char 的出现次数?
【发布时间】:2020-08-29 10:50:32
【问题描述】:

我有一个输入 [String] 如下:

main = do
  let res = calcCounts ["IOIOOIOOI\r","OOIIIOOO\r",...]

我想使用非统一的基本系统按顺序计数IO 实例。

我创建了一个Type

data OutputState = OutputState { totNumI :: Int,
                                 totNumO :: Int,
                                 numI :: Int,
                                 numO :: Int
                               } deriving (Show)

到目前为止,我创建的代码尝试单步执行输入并每次创建一个新的OutputState,同时考虑之前的OutputState,然后再达到每个[Char] 的完整条件'\r'[String] 的列表末尾但不完整:

calcCounts :: [String] -> [OutputState]
calcCounts input = map genOutputState input

genOutputState :: [Char] -> OutputState
genOutputState (x:xs)
  | x == '\r' = --return final OutputState 
  | otherwise do                 
      let currOutputState = incrementOutputState x
      genOutputState xs --also pass current OutputState back each recursion

incrementOutputState :: OutputState -> Char -> OutputState
incrementOutputState pos@prevOS x = do
  | if x == 'I' = do 
      let currOutputState = OutputState pos{totNumA} pos{totNumB} pos{numA}+1 pos{numB}
      | if currOutputState{numA} == 4 = OutputState currOutputState{totNumA}+1 currOutputState{totNumB} 0 0         
  | otherwise = do 
      let currentOutputState = OutputState pos{totNumA} pos{totNumB} pos{numA} pos{numB}+1
      | if currentOutputState{numB} == 4 = OutputState currOutputState{totNumA} currOutputState{totNumB}+1 0 0

最终输出应该是[OutputState,OutputState,..]

我知道我的代码目前不合法并且缺少逻辑。对此表示歉意。总的来说,我仍在回归 Haskell 和函数式编程。在命令式范例中,我会使用可变变量来跟踪必要的计数,但要理解这不是从功能意义上考虑问题的正确方法。

非常感谢任何帮助!

【问题讨论】:

  • 我不太明白你到底想做什么。您能否详细说明totNumAnumA 之间的区别? genOutputState "IOIOOIOOI\r" 的结果应该是什么?
  • pos{totNumA} pos{totNumB} pos{numA}+1 pos{numB} 无效。例如,您只需在 pos@OutputState {totNumA=a, totNumB=b} 上进行模式匹配,然后在表达式中写入 pos {totNumA = a+1}
  • 对@RikVanToor 感到抱歉,所需的输出将是[OutputState,OutputState,..],例如,内容将是{ totNumI=1, totNumO=1, numI=0, num0=0 }。我已将 OutputState 从 As 和 Bs 更改为 Is 和 Os 以更有意义。
  • 感谢@WillemVanOnsem,我明白你的意思,但我的语法很弱。我在使用OutputState 时遇到了很多麻烦。例如,它当前没有从genOutputState 传递到incrementOutputState,因为递归会导致let currOutputState = incrementOutputState (OutputState 0 0 0 0) xChar 中的每个OutputState 重置OutputState
  • 不清楚你想做什么。我认为只是计算列表中的相等元素。只是,使用Data.Map 作为累加器和insertwith (+) 作为函数折叠列表应该可以工作。我没有得到不统一的基础

标签: haskell recursion functional-programming conditional-statements immutability


【解决方案1】:

我认为这可以满足您的要求,尽管我仍然不完全确定我是否理解正确。

data OutputState = OutputState { totNumI :: Int,
                                 totNumO :: Int,
                                 numI :: Int,
                                 numO :: Int
                               } deriving (Show)

genOutputState :: String -> OutputState
genOutputState = foldl incrementOutputState (OutputState 0 0 0 0)

incrementOutputState :: OutputState -> Char -> OutputState
incrementOutputState (OutputState ti to 3 no)  'I' = OutputState (ti + 1) to 0 0
incrementOutputState (OutputState ti to ni no) 'I' = OutputState ti to (ni + 1) no
incrementOutputState (OutputState ti to ni 3)  'O' = OutputState ti (to + 1) 0 0
incrementOutputState (OutputState ti to ni no) 'O' = OutputState ti to ni (no + 1)
incrementOutputState os _                          = os -- Do not increment anything for characters other than 'I' and 'O'

我建议你多学习一些 Haskell 教程,因为我觉得你还不太了解语法和函数式思维方式。

【讨论】:

  • 我有一个后续问题希望您不介意回答。用于“通过”提供给genOutputStateString 的功能是什么?它是否像函数声明中没有引用它一样简单(即genOutputState str = ..)?感谢您的帮助。
  • @macourtney7 这就是所谓的 eta 缩减。 Eta 减少意味着(\x -> f x)f 相同。在这种情况下,这意味着getOutputState str = foldl incrementOutputState (OutputState 0 0 0 0) str也可以写成getOutputState = foldl incrementOutputState (OutputState 0 0 0 0)
猜你喜欢
  • 2019-02-26
  • 1970-01-01
  • 2015-12-07
  • 2011-05-13
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 2016-03-29
  • 2019-03-25
相关资源
最近更新 更多