是否有创建[Maybea]模拟的语法,但类型(*->*)

我试图创建一个适用于[Maybe a]. 但是, Maybe a 有 kind *,而 fmap 需要 kind * -> *。这导致了以下不幸的解决方案:

newtype Unfortunate a = Unfortunate ([Maybe a]) deriving Show

instance Functor Unfortunate
    where fmap f (Unfortunate a) = Unfortunate $ (fmap (fmap f)) a


-- |
-- >>> l = Unfortunate [Just 10, Just 1, Nothing, Just 15]
-- >>> fmap (*5) l
-- Unfortunate [Just 50,Just 5,Nothing,Just 75]

不幸的是必须创建一个newtype。我希望可以创建一个适用于 的实例,适用[Maybe a]于任何a. 即,可以称为fmap f [Just 10, Nothing].

我似乎缺少一些语法。是否可以定义这样的实例?

回答

MaybeT完全(甚至更多)您Unfortunate所做的:

?> import Control.Monad.Trans.Maybe
?> (*2) <$> MaybeT [Just 1, Just 2, Nothing]
MaybeT [Just 2,Just 4,Nothing]
?> pure 1 :: MaybeT [] Int
MaybeT [Just 1]

您还可以使用 DeriveFunctor 标志并机械派生“不幸的函子”:

?> :set -XDeriveFunctor 
?>  newtype Unfortunate a = Unfortunate ([Maybe a]) deriving (Functor, Show)
?> (*2) <$> Unfortunate [Just 1, Just 2, Nothing]
Unfortunate [Just 2,Just 4,Nothing]
?> 

如果你想走泛型路线,还有泛型函子。

编辑:

另一种选择是使用 GeneralizedNewtypeDeriving:

?> :set -XGeneralizedNewtypeDeriving 
?> (*2) <$> Unfortunate (MaybeT [Just 1, Just 2, Nothing])
Unfortunate (MaybeT [Just 2,Just 4,Nothing])

编辑2:

正如丹尼尔瓦格纳在评论中指出的那样,我们也可以使用:

?> import Data.Functor.Compose
?> (*2) <$> Compose [Just 1, Just 2, Nothing]
Compose [Just 2,Just 4,Nothing]


回答

不幸的是新类型的创建。我希望可以创建一个适用于 [Maybe a] 的实例,适用于任何 a。

已经有这样的例子了。它有效,不适用于任何 [Maybe a],但适用于任何 [a]。并且由于a可以与 统一Maybe a,因此您也可以将其用于[Maybe a]

现在,显然这实际上不是你的意思。当专门用于此类型时,fmap具有类型

(Maybe a -> Maybe b) -> [Maybe a] -> [Maybe b]

但你希望它采用一个类型的函数来(a -> b)代替。我提出这一点是为了解释为什么不能避免使用单独的类型1。您想要的类型已经有一个实例,因此您不能只定义一个新实例来替换该行为。您需要一个不同的类型来附加该实例。

正如在另一个答案中所讨论的,已经定义了一些泛型类型,可以组合这些类型来获得您想要的设置。但是你不能只使用一个裸的[Maybe a].


1您可以打开一些语言扩展来破坏类型系统以允许这样做,但这可能会产生令人惊讶的后果,我不会在这里讨论。


以上是是否有创建[Maybea]模拟的语法,但类型(*-&gt;*)的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>