[英]Applicative and Monad instances for a function type?
I have a data type that resembles Blah
below but because of a quirk with the type I cannot automatically derive Functor, Applicative, and Monad . 我有一个类似于下面的
Blah
的数据类型,但是由于这种类型的怪癖,我无法自动派生Functor,Applicative和Monad 。 So I must do it manually, but I'm not sure how. 因此,我必须手动执行此操作,但不确定如何操作。 I tried to take inspiration from the instances for
((->) a)
, but I can't quite figure out the Monad instance. 我试图从
((->) 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 -> _
Edit: Someone marked this as a duplicate of another, but I don't see where I would've gotten the answer from that. 编辑:有人将此标记为另一个的重复,但我不知道从哪里可以得到答案。 The newtype wrapper is what made this difficult.
新型包装器使这变得困难。 I looked up the
Monad
instance in base for (->) a
before I wrote this question, but the gymnastics in the answer here are what I needed. 在我写这个问题之前,我在
(->) a
基础上查找了Monad
实例,但是答案中的体操正是我所需要的。
How about 怎么样
Blah f >>= g = Blah $ \s ->
let Blah h = g $ f s in h s
You can derive
those instances. 您可以
derive
这些实例。 You just need to turn on the GeneralizedNewtypeDeriving
flag, which enables GHC to simply reuse the instance for the wrapped type. 您只需要打开
GeneralizedNewtypeDeriving
标志,这将使GHC可以简单地将实例重新用于包装类型。
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Blah a = Blah (String -> a) deriving (Functor, Applicative, Monad)
Here's how you can derive this yourself using typed holes. 这是您使用键入的孔自己得出此结果的方法。 Starting from your code, renamed a bit:
从您的代码开始,重命名了一下:
instance Monad Blah where
return = pure
f >>= g = Blah $ \s -> _
You'll get a message like this: 您会收到这样的消息:
Found hole ‘_’ with type: b
Relevant bindings include
s :: String
g :: a -> Blah b
f :: Blah a
So we need to produce a b
, given a String
, a Blah a
, and an a -> Blah b
. 因此,我们需要制作
b
,给定一个String
,一个Blah a
,以及a -> Blah b
。 Well, we already know how to produce an a
from a Blah a
and a String
, by pattern-matching and applying the function in the Blah
: 好了,我们已经知道如何通过模式匹配和在
Blah
应用该函数从Blah a
和String
生成a
:
Blah f >>= g = Blah $ \s -> let h = f s in _
------ -----------
Now we get: 现在我们得到:
Found hole ‘_’ with type: b
Relevant bindings include
h :: a
s :: String
g :: a -> Blah b
f :: String -> a
So we have an a
, which we can give to g
to get a Blah b
, and pattern-matching on that gives us a String -> b
: 因此,我们有一个
a
,我们可以将其赋予g
以获得Blah b
,然后进行模式匹配就可以得到一个Blah b
String -> b
:
Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in _
----------------
Now we get: 现在我们得到:
Found hole ‘_’ with type: b
Relevant bindings include
h :: String -> b
s :: String
g :: a -> Blah b
f :: String -> a
So we need a b
, and we have a String
and a String -> b
. 所以我们需要一个
b
,并且有一个String
和一个String -> b
。 That's easy: 这很容易:
Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in h s
---
And there you go, a correct implementation, guided by the types. 在类型的指导下,您可以找到正确的实现。 You may also find it clearer if you define a helper function to “run” a
Blah
: 如果您定义帮助程序功能来“运行”
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.