Functor fmap,模式匹配函数值,haskell

Functor fmap, pattern match function values, haskell

我有以下类型,想把它变成一个函子:

newtype SubsM a = SubsM {runSubsM :: Context -> Either Error (a, Env)}

到目前为止我得到了这个

instance Functor SubsM where
    fmap f (SubsM a)  =  SubsM (\s->(Right((f a),(fst s))))

我得到一个错误,因为 a 不是预期的类型,我的问题是如何在左侧进行模式匹配?

您可以在 Either Error (a, Env) 上使用 case 进行模式匹配:

instance Functor SubsM where
  fmap f (SubsM cf) = SubsM $ \c ->  case (cf c) of
    Left err -> Left err
    Right (v, env) -> Right (f v, env)

Left 的情况下传播错误,在 Right 的情况下解压结果对并将 f 应用于第一个元素。

请注意,您还可以使用 ->Either 的现有 Functor 实例来为您完成大部分工作:

instance Functor SubsM where
  fmap g (SubsM cf) = SubsM (fmap (fmap (leftfmap g)) cf)
    where
      leftfmap f (a, b) = (f a, b)

(,)Functor 实例映射到右边的值,而不是左边的值,所以你不能在那里使用 fmap。如果您从 Control.Arrow.

导入该函数,您也可以将 leftfmap 写为 first

我宁愿不用思考,当机器完全有能力为你思考时。

{-# LANGUAGE DeriveFunctor #-}

newtype SubsM a = SubsM {runSubsM :: Context -> Either Error (a, Env)}
    deriving Functor

很多必要的工作已经为您完成,因为 Either a b(,) 都是 Bifunctor class.

的实例
-- Using the tuple instance
first f (x, y) == (f x, y)

-- Using the Either instance
second g (Left err) = Left err   -- basically, id
first g (Right v) = Right (g v)

使用这些函数,您可以大大缩短这个时间(从 Lee 的回答开始逐步减少):

import Data.Bifunctor
instance Functor SubsM where
   fmap f = SubsM . second (first f) . runSubsM

真的有人会写这样的代码,更不用说从头开始写了?可能不会。它是如何工作的并不是很明显,但是可以推导出一个 一步一步非常简单,您可能会发现中间步骤之一很有用。

我可能会这样写

instance Functor SubsM where
  fmap f (SubsM cf) = SubsM $ \c -> (second . first) f (cf c)

将更深奥的部分限制为单一功能(second . first)


缩写形式的推导

首先,使用(,)Bifunctor实例来避免模式匹配 在元组上。

-- first f (v, env) == (f v, env)
instance Functor SubsM where
   fmap f (SubsM cf) = SubsM $ \c ->  case (cf c) of
      Left err -> Left err
      Right t -> Right (first f t)

接下来,使用 Either a bBifunctor 实例来避免对 cf c 的 return 值进行模式匹配:

-- second (first f) (Left err) == Left Err
-- second (first f) (Right t) == Right (first f) t
instance Functor SubsM where
   fmap f (SubsM cf) = SubsM $ \c ->  second (first f) (cf c)

您还可以通过解包来避免对 SubsM 值进行模式匹配 它在右侧 runSubsM:

instance Functor SubsM where
   fmap f cf = SubsM $ \c ->  second (first f) ((runSubsM cf) c)

最后,我们开始应用函数组合来消除显式 尽可能提出论点。

instance Functor SubsM where
   -- fmap f cf = SubsM $ \c ->  second (first f) ((runSubsM cf) c)
   -- fmap f cf = SubsM $ \c ->  second (first f) . (runSubsM cf) $ c
   -- fmap f cf = SubsM $ second (first f) . (runSubsM cf)
   -- One more function composition allows us to drop cf as an
   -- explicit argument
   fmap f = SubsM . second (first f) . runSubsM