在haskell中选择超过2个镜头

时间:2016-05-30 09:34:56

标签: haskell lenses

我在2周内练习考试Haskell。现在我正在做一些练习,但我仍然坚持这一点。

  

实施一个给出2个镜头的函数choosing,并且应该返回一个与Either - 值一起使用的新镜头。

我给了这段代码:

type Lens s a = forall f . Functor f => (a -> f a) -> s -> f s

--------------------------------------------------------------
-- Lens s1 a             :: Functor f => a -> f a -> s1 -> f s1
-- Lens s2 a             :: Functor f => a -> f a -> s2 -> f s2
-- Lens (Either s1 s2) a :: Functor f => a -> f a -> (Either s1 s2) -> f (Either s1 s2)
--------------------------------------------------------------
choosing :: Lens s1 a -> Lens s2 a -> Lens (Either s1 s2) a
choosing lns1 lns2 = undefined

现在,我完全陷入困境。我想我应该使用fmap来解决这个问题,但我不知道如何将这两个镜头结合起来。

所以,在@shang和@klappvisor的帮助下,我找到了这个问题的完整答案:

choosing :: Lens s1 a -> Lens s2 a -> Lens (Either s1 s2) a
choosing lns1 lns2 = (\func x -> case x of
                                Left value  -> (\z -> Left $ set lns1 z value) <$> (func (view lns1 value))
                                Right value -> (\z -> Right $ set lns2 z value) <$> (func (view lns2 value)))

1 个答案:

答案 0 :(得分:2)

这是一个很好的运动问题,因为您甚至不需要了解有关镜头的任何信息来实施该解决方案。您可以按照类型进行操作。

choosing :: Lens s1 a -> Lens s2 a -> Lens (Either s1 s2) a
choosing lns1 lns2 = undefined

返回类型Lens (Either s1 s2) aforall f . Functor f => (a -> f a) -> Either s1 s2 -> f (Either s1 s2)的别名,因此您知道必须返回某种带有两个参数的函数:

choosing lns1 lns2 = \func x -> undefined

func的类型为(a -> f a)x的类型为Either s1 s2。我们对func做了很多事情,但我们对x了解得足够多,我们可以对其进行模式匹配:

choosing lns1 lns2 = \func x -> case x of
    Left l  -> undefined
    Right r -> undefined

现在,使用lns1lns2func以及类型f是仿函数的知识(因此您可以使用fmap)需要实现case表达式的分支,以便两者都生成类型为f (Either s1 s2)的值。