简体   繁体   English

函数类型的适用实例和Monad实例?

[英]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 aString生成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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM