Учебник по Haskell Lens с траверсом

Я пытаюсь следовать этому руководству: http://blog.jakubarnold.cz/2014/08/06/lens-tutorial-stab-traversal-part-2.html

Я использую следующий код, который загружаю в ghci:

{-# LANGUAGE RankNTypes, ScopedTypeVariables  #-}

import Control.Applicative
import Data.Functor.Identity
import Data.Traversable

-- Define Lens type.
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t 
type Lens' s a = Lens s s a a 

-- Lens view function. Omitting other functions for brevity.
view :: Lens s t a b -> s -> a
view ln x = getConst $ ln Const x

-- Tutorial sample data types
data User = User String [Post] deriving Show
data Post = Post String deriving Show

-- Tutorial sample data
john = User "John" $ map (Post) ["abc","def","xyz"]
albert = User "Albert" $ map (Post) ["ghi","jkl","mno"]
users = [john, albert]

-- A lens
posts :: Lens' User [Post]
posts fn (User n ps) = fmap (\newPosts -> User n newPosts) $ fn ps

Оттуда работают такие простые вещи:

view posts john

Однако, когда я пытаюсь сделать следующий шаг, он не работает:

view (traverse.posts) users

Я получил:

Could not deduce (Applicative f) arising from a use of ‘traverse’
from the context (Functor f)
  bound by a type expected by the context:
             Functor f => ([Post] -> f [Post]) -> [User] -> f [User]
  at <interactive>:58:1-27
Possible fix:
  add (Applicative f) to the context of
    a type expected by the context:
      Functor f => ([Post] -> f [Post]) -> [User] -> f [User]
In the first argument of ‘(.)’, namely ‘traverse’
In the first argument of ‘view’, namely ‘(traverse . posts)’
In the expression: view (traverse . posts) users

Я вижу, что Lens имеет ограничение типа Functor, а traverse имеет более ограниченное ограничение типа для f как Applicative. Почему именно это не работает и почему учебник в блоге предполагает, что это работает?


person clay    schedule 10.12.2014    source источник
comment
Если вы удалите свои определения Lens, Lens' и view и вместо этого импортируете их из Control.Lens, это сработает, хотя остается вопрос, почему ваши не работают.   -  person icktoofay    schedule 11.12.2014


Ответы (1)


view на самом деле имеет менее строгий тип, чем Lens s t a b -> s -> a.

Если вы отбросите сигнатуру типа, ghci сообщит вам тип для view

:t view
view :: ((a1 -> Const a1 b1) -> t -> Const a b) -> t -> a

Это менее ограничительно, потому что Lens должен быть определен forall функторами, а первый аргумент для просмотра должен быть определен только для Const a1.

Если мы переименуем переменные типа на основе имен из Lens и ограничим a1 ~ a, эта подпись будет иметь больше смысла.

type Lens s t a b = forall f. Functor f =>
         (a -> f       b) -> s -> f       t 
view :: ((a -> Const a b) -> s -> Const a t) -> s -> a
view ln x = getConst $ ln Const x
person Cirdec    schedule 10.12.2014