14

我有一个函数说 foo :: [Integer] -> Bool ,但它只有在传入参数对某些条件有效时才有效,否则它应该立即终止。

 foo x | not $ isSorted x = False
       | otherwise = some_recursive_stuff_here
       where
            isSorted ax = ax == sort ax

等等

但是我不想每次都检查不变量是否已排序。除了引入另一个内部功能之外,有没有一种很好的方法来处理?

4

1 回答 1

21

您可以通过创建一个newtype.

newtype Sorted a = Sorted { fromSorted :: [a] }

sorted :: Ord a => [a] -> Sorted a
sorted = Sorted . sort

foo :: Sorted Integer -> Bool
foo (Sorted as) -> some_recursive_stuff_here

如果您将Sorted构造函数隐藏在单独的模块中,那么您的代码的用户将无法使用foo,除非先创建排序证明。他们也无法做到,sort因此Sorted您可以确定它只发生过一次。

如果您愿意,您甚至可以支持证明维护操作。

instance Monoid (Sorted a) where
  mempty = Sorted mempty
  mappend (Sorted as) (Sorted bs) = Sorted (go as bs) where
    -- lazy stable sort
    go :: Ord a => [a] -> [a] -> [a]
    go [] xs = xs
    go xs [] = xs
    go (x:xs) (y:ys) | x == y = x : y : go xs     ys
                     | x <  y = x     : go xs     (y:ys)
                     | x >  y =     y : go (x:xs) ys

(此代码现在在 Hackage 上可用:http: //hackage.haskell.org/package/sorted

于 2013-11-08T22:49:35.430 回答