我习惯使用a <> b
a
和b
作为参数。
> const ["a"] <> const ["b"] $ True
["a","b"]
为什么没有a <|> b
?
> const ["a"] <|> const ["b"] $ True
<interactive>:64:13:
No instance for (Alternative ((->) Bool))
arising from a use of ‘<|>’
In the expression: const ["a"] <|> const ["b"]
In the expression: const ["a"] <|> const ["b"] $ True
In an equation for ‘it’: it = const ["a"] <|> const ["b"] $ True
答案 0 :(得分:4)
我们想表达类似“如果结果类型是Alternative
,那么返回该类型的函数也是Alternative
”。但是,这是不对的,因为只有* -> *
类型可以是Alternative
。
我们可能会尝试通过说某些f a
的结果类型应为Alternative f
来解决我们的问题,但这仍然不好,因为我们要为其定义实例的类型也必须有善意* -> *
。
实际上,我们只想为Alternative
和某些((->) r)
的组合定义Alternative f
个实例。我们可以稍微概括一下这个概念:
import Data.Functor.Compose
instance (Applicative f, Alternative g) => Alternative (Compose f g) where
empty = Compose $ pure empty
Compose a <|> Compose b = Compose $ liftA2 (<|>) a b
不幸的是Alternative
库中的Compose f g
已经有了transformers
instance个不同的版本,它与上述实例发生了冲突。
或者,我们可以注意到ReaderT r m
与Compose ((->) r) m
(模newtype
包装)相同,幸运的是,正确的实例已由transformers
导出:< / p>
instance Alternative m => Alternative (ReaderT r m)
所以我们可以做到以下几点:
import Control.Monad.Reader
runReaderT (lift ["a"] <|> lift ["b"]) True
-- ["a", "b"]
runReaderT (empty <|> lift (Just 0)) True
-- Just 0