2015-06-09 2 views
3

Я немного смущен и не знаю, где искать информацию/объяснение следующей «проблемы» (это не проблема сама по себе, а скорее ситуация, когда Я не понимаю, что случилось за кадром):Объектив Haskell: давайте связывание Traversal '

у меня есть стек монада трансформатор с StateT. В какой-то момент в моей функции я хотел бы привязать небольшую часть моего состояния к локальной переменной, чтобы я мог ссылаться на нее вместо того, чтобы записывать весь путь к куску интересующего меня состояния. Вот что я означают:

{-# LANGUAGE ScopedTypeVariables #-} 

... 

someFunction :: MyMonad() 
someFunction = do 
    ... 
    let x :: Traversal' MyState MyDataT = myState.clients.ix clientIdx.someData.ix dataIdx 
    ... 

Теперь это не компилируется:

Couldn't match type ‘(MyDataT -> f0 MyDataT) 
        -> MyState -> f0 MyState’ 
       with ‘forall (f :: * -> *). 
        Control.Applicative.Applicative f => 
        (MyDataT -> f MyDataT) -> MyState -> f MyState’ 

Но если перенести привязку этого блока данных в функцию, то все компилируется нормально:

someFunction :: MyMonad() 
someFunction = do 
    ... 
    let x = clientData clientIdx dataIdx 
    ... 

    where clientData :: Int -> Int -> Traversal' MyState MyDataT 
     clientData clientIdx dataIdx = myState.clients.ix clientIdx.someData.ix dataIdx 

Я я ищу какую-то информацию, которая поможет мне понять, что здесь происходит, почему это происходит, чтобы я знал, что я делаю неправильно. В основном я хотел бы расширить свои знания, чтобы понять этот вариант использования немного лучше.

ответ

6

Ключевым моментом здесь является то, что аннотация должна быть отдельной строкой. Если мы это сделаем, то у нас есть привязка с явным типом, что касается GHC.

someFunction :: MyMonad() 
someFunction = do 
    ... 
    let x :: Traversal' MyState MyDataT 
     x = myState.clients.ix clientIdx.someData.ix dataIdx 
    ... 

То, что вы впервые попробовали очень редко работает, как вы хотели:

let x :: Traversal' MyState MyDataT = ... 

Это связывание без явного типа; аннотация внутри с левой стороны. GHC считает тип переменной фиксированной, прежде чем смотреть на правую сторону, но аннотация применяется только к левой стороне, поэтому GHC просто вводит тип для правой стороны отдельно, а затем пытается сопоставить его точно с аннотацией , Это делает проверку типа неудачной для всех, кроме простейших не полиморфных случаев.

Правильный способ положить аннотации внутри привязок заключается в следующем:

let x = ... :: Traversal' MyState MyDataT 

Здесь GHC первым присваивает «податливый» неопределенный переменный типа в x, затем выводит тип для правой стороны информированного в аннотации там, затем объединяет тип x с ним.

Это по-прежнему привязка без явного типа, но она работает вообще, если мы включили NoMonomorphismRestriction, по причинам, указанным в этом SO question.

+0

Большое спасибо, это было очень полезно – ksaveljev

Смежные вопросы