是否有用于创建 [Maybe a] 模拟的语法,但是类型 (* -> *)
Is there syntax for creating [Maybe a] analog, but of kind (* -> *)
我试图创建一个适用于 [Maybe a]
的 fmap。但是,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]
λ>
如果你想走仿制药路线,还有generic-functor。
编辑:
另一个选项是使用 GeneralizedNewtypeDeriving:
λ> :set -XGeneralizedNewtypeDeriving
λ> (*2) <$> Unfortunate (MaybeT [Just 1, Just 2, Nothing])
Unfortunate (MaybeT [Just 2,Just 4,Nothing])
编辑2:
正如 Daniel Wagner 在评论中指出的,我们还可以使用:
λ> import Data.Functor.Compose
λ> (*2) <$> Compose [Just 1, Just 2, Nothing]
Compose [Just 2,Just 4,Nothing]
What is unfortunate is the creation of the newtype. I'd expect it to be possible to create an instance that works for [Maybe a], for any a.
已经有这样的例子了。它不仅适用于任何 [Maybe a],而且适用于任何 [a]。由于 a
可以与 Maybe a
统一,因此您也可以将其用于 [Maybe a]
。
现在,显然这实际上不是您的意思。当专用于此类型时,fmap
具有类型
(Maybe a -> Maybe b) -> [Maybe a] -> [Maybe b]
但您希望它采用类型为 (a -> b)
的函数。我提出这个是为了解释为什么无法避免使用单独的类型1。您想要的类型已经有一个实例,因此您不能只定义一个新实例来替换该行为。您需要一个不同的类型来附加该实例。
正如在另一个答案中所讨论的,已经定义了泛型类型,可以组合它们以获得您想要的设置。但是你不能只使用裸 [Maybe a]
.
1 您可以打开一些语言扩展来打破类型系统以允许这样做,但这可能会产生令人惊讶的后果,我不会在这里深入探讨.
这是 DerivingVia
的完美用例(引起我注意的是我没有足够仔细地阅读问题,你必须以一种或另一种方式使用 newtype
: 这个解决方案不是你所希望的,但它是惯用的)
{-# Language DerivingVia #-}
{-# Language StandaloneKindSignatures #-}
import Control.Applicative (Alternative)
import Control.Monad (MonadPlus)
import Control.Monad.Fix (MonadFix)
import Control.Monad.Trans.Maybe
import Control.Monad.Zip (MonadZip)
import Data.Kind (Type)
type Fortunate :: Type -> Type
newtype Fortunate a = Fortunate [Maybe a]
deriving
( Functor, Foldable, Applicative, Alternative
, Monad, MonadPlus, MonadFail, MonadFix, MonadZip
)
via MaybeT []
其中一些实例,例如 (Functor, Foldable, Applicative, Alternative)
可以通过 Compose Maybe []
导出。
要列出可以派生的实例,请使用 :instances
命令
>> :instances MaybeT []
instance [safe] Alternative (MaybeT [])
-- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Applicative (MaybeT [])
-- Defined in ‘Control.Monad.Trans.Maybe’
...
>> :instances Compose Maybe []
instance Alternative (Compose Maybe [])
-- Defined in ‘Data.Functor.Compose’
instance Applicative (Compose Maybe [])
-- Defined in ‘Data.Functor.Compose’
...
因为 Fortunate
是一个应用程序,您可以通过逐点(惯用的,应用程序的)提升推导 (Semigroup, Monoid, Num, Bounded)
:
import Data.Monoid (Ap(..))
..
deriving (Semigroup, Monoid, Num, Bounded)
via Ap Fortunate a
其中 (<>) = liftA2 (<>)
、abs = liftA abs
、mempty = pure mempty
、minBound = pure minBound
。
我试图创建一个适用于 [Maybe a]
的 fmap。但是,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]
λ>
如果你想走仿制药路线,还有generic-functor。
编辑:
另一个选项是使用 GeneralizedNewtypeDeriving:
λ> :set -XGeneralizedNewtypeDeriving
λ> (*2) <$> Unfortunate (MaybeT [Just 1, Just 2, Nothing])
Unfortunate (MaybeT [Just 2,Just 4,Nothing])
编辑2:
正如 Daniel Wagner 在评论中指出的,我们还可以使用:
λ> import Data.Functor.Compose
λ> (*2) <$> Compose [Just 1, Just 2, Nothing]
Compose [Just 2,Just 4,Nothing]
What is unfortunate is the creation of the newtype. I'd expect it to be possible to create an instance that works for [Maybe a], for any a.
已经有这样的例子了。它不仅适用于任何 [Maybe a],而且适用于任何 [a]。由于 a
可以与 Maybe a
统一,因此您也可以将其用于 [Maybe a]
。
现在,显然这实际上不是您的意思。当专用于此类型时,fmap
具有类型
(Maybe a -> Maybe b) -> [Maybe a] -> [Maybe b]
但您希望它采用类型为 (a -> b)
的函数。我提出这个是为了解释为什么无法避免使用单独的类型1。您想要的类型已经有一个实例,因此您不能只定义一个新实例来替换该行为。您需要一个不同的类型来附加该实例。
正如在另一个答案中所讨论的,已经定义了泛型类型,可以组合它们以获得您想要的设置。但是你不能只使用裸 [Maybe a]
.
1 您可以打开一些语言扩展来打破类型系统以允许这样做,但这可能会产生令人惊讶的后果,我不会在这里深入探讨.
这是 DerivingVia
的完美用例(引起我注意的是我没有足够仔细地阅读问题,你必须以一种或另一种方式使用 newtype
: 这个解决方案不是你所希望的,但它是惯用的)
{-# Language DerivingVia #-}
{-# Language StandaloneKindSignatures #-}
import Control.Applicative (Alternative)
import Control.Monad (MonadPlus)
import Control.Monad.Fix (MonadFix)
import Control.Monad.Trans.Maybe
import Control.Monad.Zip (MonadZip)
import Data.Kind (Type)
type Fortunate :: Type -> Type
newtype Fortunate a = Fortunate [Maybe a]
deriving
( Functor, Foldable, Applicative, Alternative
, Monad, MonadPlus, MonadFail, MonadFix, MonadZip
)
via MaybeT []
其中一些实例,例如 (Functor, Foldable, Applicative, Alternative)
可以通过 Compose Maybe []
导出。
要列出可以派生的实例,请使用 :instances
命令
>> :instances MaybeT []
instance [safe] Alternative (MaybeT [])
-- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Applicative (MaybeT [])
-- Defined in ‘Control.Monad.Trans.Maybe’
...
>> :instances Compose Maybe []
instance Alternative (Compose Maybe [])
-- Defined in ‘Data.Functor.Compose’
instance Applicative (Compose Maybe [])
-- Defined in ‘Data.Functor.Compose’
...
因为 Fortunate
是一个应用程序,您可以通过逐点(惯用的,应用程序的)提升推导 (Semigroup, Monoid, Num, Bounded)
:
import Data.Monoid (Ap(..))
..
deriving (Semigroup, Monoid, Num, Bounded)
via Ap Fortunate a
其中 (<>) = liftA2 (<>)
、abs = liftA abs
、mempty = pure mempty
、minBound = pure minBound
。