Реализовать выбор более 2 линз в Haskell

Я готовлюсь к экзамену Haskell через 2 недели. Сейчас я делаю несколько упражнений, но я застрял на этом.

Реализуйте функцию 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 для решения этой проблемы, но я не знаю, как объединить эти 2 объектива.

Итак, с помощью @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)))

person Community    schedule 30.05.2016    source источник
comment
если вам не повезло и вы хотите увидеть решение, перейдите по этой ссылке и внимательно прочитайте хорошая статья о линзах с точным указанием вашего упражнения в ней   -  person klappvisor    schedule 30.05.2016
comment
@klappvisor: спасибо! Статья действительно полезная :)   -  person    schedule 30.05.2016


Ответы (1)


Это отличная задача для упражнений, потому что вам даже не нужно ничего знать о линзах, чтобы реализовать решение. Вы можете просто следовать типам.

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

Тип возвращаемого значения Lens (Either s1 s2) a является псевдонимом для forall 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

Теперь, используя lns1, lns2, func и знание того, что тип f является функтором (поэтому вы можете использовать fmap), вам просто нужно реализовать ветви case-выражения, чтобы оба производили значение типа f (Either s1 s2).

person shang    schedule 30.05.2016
comment
Большое спасибо! Это очень понятное объяснение :) - person ; 30.05.2016