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

时间:2016-09-15 15:32:11

标签: function haskell pattern-matching functor

我有以下类型,并希望将其作为Functor:

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不是预期的类型,我的问题是我如何在左侧模式匹配a?

4 个答案:

答案 0 :(得分:7)

当机器完全能够为你思考时,我宁愿不去思考。

{-# LANGUAGE DeriveFunctor #-}

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

答案 1 :(得分:5)

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

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

Functor (,)实例映射在右侧值上,而不是左侧值,因此您无法使用fmap。如果您从leftfmap导入该功能,也可以将first写为Control.Arrow

答案 2 :(得分:3)

您可以使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应用于第一个元素。

答案 3 :(得分:3)

由于Either a b(,)都是Bifunctor类的实例,因此已经完成了大部分必要的工作。

-- 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)

使用这些功能,你可以大大缩短这个功能(从李的答案开始逐步减少):

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的{​​{1}}实例来避免模式匹配 在元组上。

(,)

接下来,使用-- 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) Bifunctor实例来避免Either a b的返回值上的模式匹配:

cf c

您还可以通过解包来避免-- 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)