2016-04-19 8 views
1
{-# LANGUAGE TemplateHaskell  #-} 

import Control.Lens 

data Fruit = Fruit 
    { _fruitColor :: String 
    } 

$(makeClassy ''Fruit) 

data Fruits = 
    Banana Int Fruit 
    | Strawberry String Fruit 

printer :: HasFruit s => s -> IO() 
printer f = putStrLn $ f ^. fruitColor 

sample :: IO() 
sample = do 
    printer $ Fruit "yellow" 
    printer $ Banana 5 $ Fruit "yellow" 

私はコア製品タイプ、フルーツを持っています。私はすべてコアタイプの製品であるFruitを含むデータ型を持っていますが、Fruits型で表すことができるようにしたいと考えています。和型のFruitsを使用して、コア製品タイプのコンポーネント、Fruitにアクセスしたいと考えています。つまり、バナナやストロベリーのようなタイプをHasFruitのインスタンスにしたいと思います。レンズタイプの合計(製品タイプを含む)

FruitsにHasFruitをインスタンス化させる簡単な方法はありますか?これを表現するための良いパターンがありますか?コアタイプの商品タイプはサムタイプですか?

+1

レンズパッケージは、このようなインスタンスを導き出すことができるかどうかはわからないが、あなたはそれを自分で書くことができます: 'インスタンスHasFruit果物どこフルーツK(バナナのx F)=バナナのx <$> K F;フルーツk(イチゴx f)=イチゴx <$> k f'。バナナとイチゴは種類ではなく、種類ではないのでクラスのインスタンスにすることはできません。それらは 'Fruit'型の値を返すコンストラクタです。 – user2407038

答えて

1

は、それはこのように何かをするより理にかなって:

data FruitType = Banana Int | Strawberry String 

data Fruits = Fruits { _fruitsFruitType :: FruitType, _fruitsFruit :: Fruit } 

makeFields ''Fruits 

-- `Fruits` now instantiates `HasFruit` 

はまたFruitType用プリズムを作りたいかもしれません。プリズムは本質的に、サムタイプの異なる部分にトラバースされますが、それらを使用して構築することもできます。

makePrisms ''FruitType 

-- double the int if the argument is a `Banana` 

doubleBanana = fruitType._Banana *~ 2 
関連する問題