2015-02-13 3 views
3

Я хочу использовать строковый литерал как Traversal, но я немного потерян в типах. Возможно ли создать этот экземпляр?Можно ли сделать Traversal экземпляром IsString

import Control.Lens 
import Data.Aeson 
import Data.Aeson.Lens 
import Data.String 
import Data.Default 

{- Having: 
key' :: AsValue t => Text -> Traversal' t (Maybe Value) 
_JSON :: (ToJSON a, FromJSON a) => Traversal' t a 
-} 

instance (AsValue t, FromJSON v, ToJSON v, Default v) => IsString (Traversal' t v) where 
    fromString k = key' (fromString k) . non (toJSON def) . _JSON 

Чтобы достичь чего-то вроде этого внутри государственного монады:

"some-key" .= (3 :: Int) 

Проблема с экземплярами универсально количественными типа. Благодаря!

ответ

5

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

fromStringTraversal :: (AsValue t, FromJSON v, ToJSON v, Default v) 
        => String -> Traversal' t v 
fromStringTraversal = undefined 

Затем написать свой экземпляр, просто встраивать определение Traversal' в голову экземпляра. Это работает, потому что любые переменные типа в экземпляре универсально квантуются неявно.

{-# LANGUAGE RankNTypes, FlexibleInstances, GADTs #-} 

instance (a ~ a', b ~ b', AsValue b, Default a, FromJSON a, ToJSON a, Applicative f) 
     => IsString ((a -> f a') -> b -> f b') where 
    fromString = fromStringTraversal 

The a ~ a', b ~ b' ограничения могут быть перемещены из контекста в голову экземпляра, но этот способ дает лучшее определение типа. Тогда

{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-} 

-- Infered type: 
-- test :: (AsValue s, MonadState s m) => m() 
test = "some-key" .= (3 :: Int) 
+1

Этот пример также требует 'RankNTypes' говорить о синонимов типа объектива,' FlexibleInstances' для 'экземпляра IsString', либо' TypeFamilies' или '' GADTs' для ~ 'и' прячась ((. =)) 'при импорте' Data.Aeson'. – Cirdec