根据我的理解,元组上的延迟模式匹配只是推迟了(,)
构造函数的解析......如果我们立即使用这两个字段,那么真的有任何缺点吗?无论如何它都会得到解决......
是否有理由不使用延迟模式匹配?
foo ~(x, y) = x + y
-- vs
foo (x, y) = x + y
您何时更愿意使用第二个?
编辑:我特别感兴趣的是只有一种模式并且模式总是匹配的情况。
答案 0 :(得分:7)
如果您想在惰性模式中进行任何严格匹配,则不希望使用延迟模式匹配。例如,鉴于这些定义:
foo' (Just x, Just y) = Just (x + y)
foo' _ = Nothing
foo ~(Just x, Just y) = Just (x + y)
foo _ = Nothing
foo' (Just 5, Nothing)
给出Nothing
,但foo (Just 5, Nothing)
会抛出运行时错误 - 另外还会发出编译时警告,_
情况是多余的,因为~(…)
} case是无可辩驳的。
当你知道模式总是匹配时,使用延迟模式匹配几乎是有意义的,这基本上意味着你只是在整个惰性模式中使用单构造函数类型,例如(,)
。
答案 1 :(得分:7)
一个例子是State monad。 State Monad的严格/懒惰版本通过它们在绑定期间对(值,状态)对进行模式匹配来区分。
Strict州monad:
m >>= k = StateT $ \ s -> do
(a, s') <- runStateT m s
runStateT (k a) s
Lazy州monad:
m >>= k = StateT $ \ s -> do
~(a, s') <- runStateT m s
runStateT (k a) s'
懒惰状态monad中的惰性模式匹配允许您定义像这样的奇怪程序(取自Melding Monads的this blog post):
pro :: State [Bool] ()
pro = do
pro
s <- get
put (True : s)
程序使用“头递归”生成True
值的惰性无限列表。使用严格状态monad的相同程序会在生成任何内容之前将堆栈清空。
答案 2 :(得分:1)
懒惰有性能成本。有时,它具有性能优势。有严格的State
monad danidiaz提及存在的原因;延迟和延迟意味着最终可能会耗尽内存,或者导致缓存性能下降。你必须考虑每种情况下发生的事情。一个好的经验法则是模式匹配应该是严格的,除非有特定的理由让它们变得懒惰。如果有疑问,或者性能至关重要,请尝试使用两种方式进行基准测试和/或分析。
答案 3 :(得分:0)
需要~
的示例:由于懒惰,您可以折叠这样的无限结构以获得第一个元素:
foldMap (First . Just) [(1::Int)..]
但是,如果您想使用Monoid
(a, b)
实例一次计算两个此类结果,则会失败:
foldMap (\x -> (First (Just x), First (Just x))) [(1::Int)..]
永远不会结束。原因是mappend
的{{1}}定义中的非延迟模式匹配:
(,)
但是,使用延迟匹配定义相同的monoid
instance (Monoid a, Monoid b) => Monoid (a,b) where
mempty = (mempty, mempty)
(a1,b1) `mappend` (a2,b2) = (a1 `mappend` a2, b1 `mappend` b2)
按预期工作:
newtype LazyTuple a b = LazyTuple (a, b)
deriving (Eq, Ord, Show, Read)
instance (Monoid a, Monoid b) => Monoid (LazyTuple a b) where
mempty = LazyTuple (mempty, mempty)
LazyTuple (~(x1, y1)) `mappend` LazyTuple (~(x2, y2))
= LazyTuple (x1 <> x2, y1 <> y2)
立即结束。