函数类型的Applicative和Monad实例?

时间:2016-10-26 15:13:17

标签: haskell monads instances

我的数据类型类似于下面的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个实例,但是答案中的体操就是我需要的。

3 个答案:

答案 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

因此,我们需要生成bStringBlah aa -> Blah b。好吧,我们已经知道如何通过模式匹配并在a中应用函数来从Blah aString生成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