我的数据类型类似于下面的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 -> _
编辑:有人将此标记为另一个副本,但我不知道从哪里可以得到答案。 newtype包装器使这很困难。在我写这个问题之前,我在Monad
的基础上查找了(->) a
个实例,但是答案中的体操就是我需要的。
答案 0 :(得分:3)
怎么样
Blah f >>= g = Blah $ \s ->
let Blah h = g $ f s in h s
答案 1 :(得分:2)
您可以derive
这些实例。您只需要打开GeneralizedNewtypeDeriving
标志,这样就可以让GHC简单地为包装类型重用该实例。
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Blah a = Blah (String -> a) deriving (Functor, Applicative, Monad)
答案 2 :(得分:1)
以下是使用打字孔自己推导出来的方法。从您的代码开始,重命名为:
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
。好吧,我们已经知道如何通过模式匹配并在a
中应用函数来从Blah a
和String
生成Blah
:
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
---
然后你去,一个正确的实现,由类型指导。如果您定义一个帮助函数来“运行”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