函数组合与noob lambdas使用Parsers在fmap仿函数实例中发生冲突

时间:2015-09-02 08:43:36

标签: haskell

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

first :: (a -> b) -> (a, c) -> (b, c)
first f (a, c) = (f a, c)

inParser f = Parser . f . runParser

-- My solution
instance Functor Parser where
  fmap g (Parser f) = Parser (\xs -> fmap (first g) (f xs))


-- Second solution
instance Functor Parser where
  fmap = inParser . fmap . fmap . first

上面有两个fmap定义,它们是如何相同的?

您能解释第二种解决方案的工作原理吗?

这里问的同样问题:Implementing Parser Functor

2 个答案:

答案 0 :(得分:3)

您的解决方案适用于fmap的{​​{1}}实例,我认为您理解正确吗?

第二个很难得到 - 所以也许值得重新引入一些Maybe .. (

首先让我们为)添加签名:

inParser

你可以看到这真的只是解开/包装问题的内核;) - 使用它你可以集中精力处理inParser :: ((String -> Maybe (a, String)) -> (String -> Maybe(b, String))) -> Parser a -> Parser b

其他部分(String -> Maybe (a,String)fmap)出于同样的原因:他们展开的东西,直到你可以到first行动它:

a

记住fmap :: (a -> b) -> Parser a -> Parser b fmap f p { def } = inParser (fmap . fmap $ first f) $ p { def inParser } = Parser . (fmap . fmap $ first f) . runParser $ p 需要runParser p并返回String

Maybe (a, String)first f(a,c) -> (b,c),第一个(a,String) -> (b,String)使用fmap - 仿函数实例将其转换为Maybe }。

下一个Maybe (a,String) -> Maybe (b,String)会使用fmap仿函数实例将String -> Maybe (a, String)翻译为String -> Maybe (b, String)

最后(->) String再次将它包起来。

我希望这有点帮助。

话虽如此,你的版本可以说更具可读性,而第二个是一个很好的脑筋急转弯,似乎更简洁/ Haskelly我更喜欢第一个版本;)

答案 1 :(得分:1)

解密无点代码的有用方法,例如

fmap = inParser . fmap . fmap . first

要忘记代码实际在做什么,只看一下类型。

我们从类型

的函数开始
fun :: a -> b

假设这是我们定义的fmap操作的参数。我们应用first,将其类型更改为

first $ fun :: (a, String) -> (b, String)

上面,我通过查看解析器的类型猜测第二个组件是String。然后我们应用fmap ...因为解析器的定义中有Maybe,我们猜测必须在该类型中完成:

fmap . first $ fun :: Maybe (a, String) -> Maybe (b, String)

另一个fmap。现在我们猜它必须在(->) String仿函数:

fmap . fmap . first $ fun :: (String -> Maybe (a, String)) -> 
                             (String -> Maybe (b, String))

最后,inParser包含在newtype

inParser . fmap . fmap . first $ fun :: Parser a -> Parser b

因此:

inParser . fmap . fmap . first :: (a -> b) -> Parser a -> Parser b

瞧。

注意我们需要通过查看解析器的类型来猜测一些事情。这使得代码难以阅读,除非您知道什么是最终目的地类型。

为此,我不建议在这种情况下使用无点样式。