Где находится документация для автогенерации Имеются ли очки типов в объективе? - PullRequest
0 голосов
/ 25 февраля 2019

Я смотрел на предпоследний пример в этом сообщении в блоге (также здесь ), и после проверки его запуска, казалось, он подтверждает, что линза может генерировать классы типов Has, которые явзять был подтекст от автора блога.Однако мне не хватает того, где это описано, либо в содержании объектива , либо в руководстве по объективу .Любые объяснения, как это делается за пределами официальных документов, также приветствуются.Но кажется, что это может быть просто стандартом при использовании самой базовой функции (makeLenses, или в данном случае makeLensesWith).

Вот воспроизведенный код:

#!/usr/bin/env stack
-- stack --resolver lts-8.12 script
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
import Control.Concurrent.Async.Lifted.Safe
import Control.Monad.Reader
import Control.Concurrent.STM
import Say
import Control.Lens
import Prelude hiding (log)

data Env = Env
  { envLog :: !(String -> IO ())
  , envBalance :: !(TVar Int)
  }

makeLensesWith camelCaseFields ''Env

modify :: (MonadReader env m, HasBalance env (TVar Int), MonadIO m)
       => (Int -> Int)
       -> m ()
modify f = do
  env <- ask
  liftIO $ atomically $ modifyTVar' (env^.balance) f

logSomething :: (MonadReader env m, HasLog env (String -> IO ()), MonadIO m)
             => String
             -> m ()
logSomething msg = do
  env <- ask
  liftIO $ (env^.log) msg

main :: IO ()
main = do
  ref <- newTVarIO 4
  let env = Env
        { envLog = sayString
        , envBalance = ref
        }
  runReaderT
    (concurrently
      (modify (+ 1))
      (logSomething "Increasing account balance"))
    env
  balance <- readTVarIO ref
  sayString $ "Final balance: " ++ show balance

1 Ответ

0 голосов
/ 25 февраля 2019

Field - это слово lens, используемое для описания шаблона одного класса для каждого именованного поля, что позволяет использовать несколько записей с одним и тем же именем поля, но (необязательно) разными типами.Так что camelCaseFields, makeFieldOptics, defaultFieldRules все говорят от своего имени, что они будут генерировать эти HasFoo классы, в обычном кратком стиле lens.

makeClassy также генерирует классы с именем Has*, но именованные в соответствии с типом данных, а не полем записи, и не по другому шаблону.

Ваш код выше генерирует следующий код (показанный с -ddump-splices):

    makeLensesWith camelCaseFields ''Env
  ======>
    class HasBalance s a | s -> a where
      balance :: Lens' s a
    instance HasBalance Env (TVar Int) where
      {-# INLINE balance #-}
      balance f_a4eTr (Env x1_a4eTs x2_a4eTt)
        = (fmap (\ y1_a4eTu -> (Env x1_a4eTs) y1_a4eTu)) (f_a4eTr x2_a4eTt)
    class HasLog s a | s -> a where
      log :: Lens' s a
    instance HasLog Env (String -> IO ()) where
      {-# INLINE log #-}
      log f_a4eTx (Env x1_a4eTy x2_a4eTz)
        = (fmap (\ y1_a4eTA -> (Env y1_a4eTA) x2_a4eTz)) (f_a4eTx x1_a4eTy)
...