Haskell写的简陋分词工具(续篇)

在上一篇博客中,我提到了自己写一个break函数,但是今天中午在想起来的时候发现当初的实现极其愚蠢,因为根本不需要独立的参数实现状态的保存。上次的代码是这样的:

1
2
3
4
5
6
7
8
9
myBreak :: (a -> Bool) -> [a] -> ([a],[a])
myBreak rule list = breakWith rule list ([],[])
  where breakWith :: (a -> Bool) -> [a] -> ([a],[a]) -> ([a],[a])
        breakWith rule list (lhs,rhs) = 
          case list of 
            []     -> (lhs,rhs)
            (x:xs) -> if rule x  
                      then (lhs,x:xs)  
                      else breakWith rule xs (lhs ++ x:[],rhs)

但是今天中午无意看到这里有一个非常蠢的设定: 我们给breakWith重复的传递了列表未被判断的部分,在代码中表现为第二个参数[a]和第三个参数([a],[a]),我们可以直接将未被判断的列表后半部分放在(,)的第二个位置。于是代码就是这样子的:

1
2
3
4
5
6
7
8
9
myBreak :: (a -> Bool) -> [a] -> ([a],[a])
myBreak foo list = breakWith foo ([],list)
  where breakWith :: (a -> Bool) -> ([a],[a]) -> ([a],[a])
        breakWith rule (lhs,rhs) = 
          case rhs of
            []     -> (lhs,rhs)
            (x:xs) -> if (rule x) 
                      then (lhs,rhs) 
                      else breakWith rule (lhs ++ x:[],xs)

通过递归一步一步的往后拆分列表,在遇到使得谓词判断为真的时候返回拆分的最终结果,而不需要额外的状态保存变量。部分减少了内存的开销。