我正在嘗試為通用型別實作到 YAML 的轉換。
我實作的簡單轉換效果很好,但我想將它們的Show實體用于data Foo = Bar | Biz.
我在想像下面這樣的事情。show它正確地捕獲了上面提到的型別,但是由于我無法正確約束它而無法呼叫。
instance {-# OVERLAPPING #-} (GToYaml x, GToYaml y) => GToYaml (D1 d (x : : y)) where
gToYaml x = string $ pack $ show $ to x
是否有可能以某種方式約束原始型別具有 Generic 和 Show 實體?還是應該以不同的方式處理?
uj5u.com熱心網友回復:
據推測,原始型別類類似于
class ToYaml x where
toYaml :: x -> Yaml
假設我們定義了這個輔助資料型別和型別類:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Proxy
import GHC.Generics
data HowToConvertToYaml = NormalCase | SpecialCase
class ToYaml' (how :: HowToConvertToYaml) x where
toYaml' :: Proxy how -> x -> Yaml
HowToConvertToYaml被用作DataKind, 提供一條額外的資訊給ToYaml': 我們是否在特殊情況下。這允許我們為每種情況定義不同的實體:
instance Show x => ToYaml' SpecialCase x where
toYaml' _ = undefined
instance (Generic x, GToYaml (Rep x)) => ToYaml' NormalCase x where
toYaml' _ = undefined
問題是我們要使用ToYaml,而不是ToYaml'。我們需要一種自動計算HowToConvertToYaml每種型別的方法,然后將 ToYaml實體委托給該型別ToYaml'。
我們可以使用型別族:
type family FindHowToConvertToYaml rep :: HowToConvertToYaml where
FindHowToConvertToYaml (D1 _ (_ : : _)) = SpecialCase
FindHowToConvertToYaml _ = NormalCase
就將ToYaml是:ToYaml'
instance (Generic x, ToYaml' (FindHowToConvertToYaml (Rep x)) x) => ToYaml x where
toYaml = toYaml' (Proxy @(FindHowToConvertToYaml (Rep x)))
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/495741.html
下一篇:創建型別的通用變體的列舉
