在Haskell中实现选择超过2个镜头

3

我正在为两周后的Haskell考试做准备。现在我正在做一些练习,但是我卡在了这个问题上。

实现一个函数choosing,它接受2个镜头,并应返回一个可用于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)))

如果你运气不好,想要查看解决方案,请访问此链接并阅读关于透镜的非常好的文章,其中包含与您的练习完全相同的内容。 - klappvisor
@klappvisor:谢谢!这篇文章真的很有用 :) - user4424299
1个回答

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)的值。

非常感谢!这是一个非常清晰的解释 :) - user4424299

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接