函数类型的 Applicative 和 Monad 实例?
Applicative and Monad instances for a function type?
我有一个类似于下面的 Blah
的数据类型,但 由于该类型的一个怪癖,我无法自动派生 Functor、Applicative 和 Monad。所以我必须手动完成,但我不确定如何。我试图从 ((->) a)
的实例中获取灵感,但我不太明白 Monad 实例。
newtype Blah a = Blah (String -> a) -- deriving (Functor, Applicative, Monad)
-- this seems right
instance Functor Blah where
fmap f (Blah g) = Blah (f . g)
instance Applicative Blah where
pure = Blah . const
-- This is right, right?
(<*>) (Blah f) (Blah g) = Blah $ \x -> f x (g x)
instance Monad Blah where
return = pure
-- I'm not having any luck here.
(>>=) a b = Blah $ \c -> _
编辑:有人将此标记为与另一个重复,但我不知道从哪里可以得到答案。新型包装器使这变得困难。在我写这个问题之前,我在 (->) a
的基础中查找了 Monad
实例,但是这里答案中的体操是我需要的。
您可以 derive
这些实例。您只需要打开 GeneralizedNewtypeDeriving
标志,这使 GHC 可以简单地重用包装类型的实例。
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Blah a = Blah (String -> a) deriving (Functor, Applicative, Monad)
怎么样
Blah f >>= g = Blah $ \s ->
let Blah h = g $ f s in h s
以下是您可以使用类型化孔自行推导的方法。从你的代码开始,改名了一下:
instance Monad Blah where
return = pure
f >>= g = Blah $ \s -> _
您会收到这样的消息:
Found hole ‘_’ with type: b
Relevant bindings include
s :: String
g :: a -> Blah b
f :: Blah a
因此我们需要生成一个 b
,给定一个 String
、一个 Blah a
和一个 a -> Blah b
。好吧,我们已经知道如何通过模式匹配和应用 Blah
:
中的函数从 Blah a
和 String
生成 a
Blah f >>= g = Blah $ \s -> let h = f s in _
------ -----------
现在我们得到:
Found hole ‘_’ with type: b
Relevant bindings include
h :: a
s :: String
g :: a -> Blah b
f :: String -> a
所以我们有一个 a
,我们可以把它给 g
来得到一个 Blah b
,然后模式匹配给我们一个 String -> b
:
Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in _
----------------
现在我们得到:
Found hole ‘_’ with type: b
Relevant bindings include
h :: String -> b
s :: String
g :: a -> Blah b
f :: String -> a
所以我们需要一个b
,我们有一个String
和一个String -> b
。这很简单:
Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in h s
---
好了,正确的实现,以类型为指导。如果你定义一个辅助函数到 “运行” a Blah
:
你可能也会发现它更清楚
newtype Blah a = Blah { runBlah :: String -> a }
-- or:
runBlah :: Blah a -> String -> a
runBlah (Blah f) = f
instance Monad Blah where
f >>= g = Blah $ \s -> runBlah (g (runBlah f s)) s
我有一个类似于下面的 Blah
的数据类型,但 由于该类型的一个怪癖,我无法自动派生 Functor、Applicative 和 Monad。所以我必须手动完成,但我不确定如何。我试图从 ((->) a)
的实例中获取灵感,但我不太明白 Monad 实例。
newtype Blah a = Blah (String -> a) -- deriving (Functor, Applicative, Monad)
-- this seems right
instance Functor Blah where
fmap f (Blah g) = Blah (f . g)
instance Applicative Blah where
pure = Blah . const
-- This is right, right?
(<*>) (Blah f) (Blah g) = Blah $ \x -> f x (g x)
instance Monad Blah where
return = pure
-- I'm not having any luck here.
(>>=) a b = Blah $ \c -> _
编辑:有人将此标记为与另一个重复,但我不知道从哪里可以得到答案。新型包装器使这变得困难。在我写这个问题之前,我在 (->) a
的基础中查找了 Monad
实例,但是这里答案中的体操是我需要的。
您可以 derive
这些实例。您只需要打开 GeneralizedNewtypeDeriving
标志,这使 GHC 可以简单地重用包装类型的实例。
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Blah a = Blah (String -> a) deriving (Functor, Applicative, Monad)
怎么样
Blah f >>= g = Blah $ \s ->
let Blah h = g $ f s in h s
以下是您可以使用类型化孔自行推导的方法。从你的代码开始,改名了一下:
instance Monad Blah where
return = pure
f >>= g = Blah $ \s -> _
您会收到这样的消息:
Found hole ‘_’ with type: b
Relevant bindings include
s :: String
g :: a -> Blah b
f :: Blah a
因此我们需要生成一个 b
,给定一个 String
、一个 Blah a
和一个 a -> Blah b
。好吧,我们已经知道如何通过模式匹配和应用 Blah
:
Blah a
和 String
生成 a
Blah f >>= g = Blah $ \s -> let h = f s in _
------ -----------
现在我们得到:
Found hole ‘_’ with type: b
Relevant bindings include
h :: a
s :: String
g :: a -> Blah b
f :: String -> a
所以我们有一个 a
,我们可以把它给 g
来得到一个 Blah b
,然后模式匹配给我们一个 String -> b
:
Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in _
----------------
现在我们得到:
Found hole ‘_’ with type: b
Relevant bindings include
h :: String -> b
s :: String
g :: a -> Blah b
f :: String -> a
所以我们需要一个b
,我们有一个String
和一个String -> b
。这很简单:
Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in h s
---
好了,正确的实现,以类型为指导。如果你定义一个辅助函数到 “运行” a Blah
:
newtype Blah a = Blah { runBlah :: String -> a }
-- or:
runBlah :: Blah a -> String -> a
runBlah (Blah f) = f
instance Monad Blah where
f >>= g = Blah $ \s -> runBlah (g (runBlah f s)) s