有没有办法将部分模式匹配与返回相结合?



我正在编写一个使用blaze-html来构造HTML文档的Haskell程序。当一个title :: Maybe TextNothing时,我想从中产生一个h1。我可以这样做:

case title of
Just t  -> H.h1 $ toHtml t
_       -> return ()

或者,在Maybe的特定情况下,我可以这样做:

when (title /= Nothing) $ H.h1 $ toHtml $ fromJust title

我可以拥有(也许带有 GHC 扩展(看起来更像第二个示例的东西,但对于任意ADT?类似于部分模式匹配的东西,只是默认为return ().我想象这样的语法:

-- imaginary syntax
when title of Just t -> H.h1 $ toHtml t

你想要的是以下类型的函数:

Applicative f => Maybe a -> (a -> f ()) -> f ()

使用Hoogle,您可以找到几个选项。所以这个函数最常见的名称似乎是whenJust.例如,您可以在relude库中找到它。

如果您对此问题的通用解决方案感兴趣,最接近的方法就是使用lens库中的棱镜。下面我提供了完整的代码和后续说明:

{-# LANGUAGE Rank2Types      #-}
{-# LANGUAGE TemplateHaskell #-}
module Prism where
import Control.Lens (Prism', makePrisms, preview)
data Foo
= Bar String
| Baz Int
| Quux Bool
makePrisms ''Foo
whenMatched :: Applicative f => Prism' s a -> s -> (a -> f ()) -> f ()
whenMatched prism val f = case preview prism val of
Nothing -> pure ()
Just a  -> f a

函数makePrisms是一个Haskell宏,需要启用TemplateHaskell扩展。此函数将生成名称为_Bar_Baz_Quux的棱镜。您可以在 GHCi 中检查它们的类型:

λ: :t _Bar
_Bar
:: (profunctors-5.3:Data.Profunctor.Choice.Choice p,
Applicative f) =>
p String (f String) -> p Foo (f Foo)
λ: :t _Baz
_Baz
:: (profunctors-5.3:Data.Profunctor.Choice.Choice p,
Applicative f) =>
p Int (f Int) -> p Foo (f Foo)

类型可能看起来很可怕,但这是因为lens库的内部结构复杂。我已经实现了whenMatched函数,它应该有助于以更简单的方式使用棱镜。以下是使用它的方法:

λ: whenMatched _Bar (Bar "foo") putStrLn 
foo
λ: whenMatched _Bar (Baz 42) putStrLn 

最新更新