環境
私たちが持っている場合
data Foo = Foo { x :: Maybe Int, y :: Maybe Text }
Applicative コンテキスト (ここでは IO) で Applicative スタイルを構築することができます。
myfoo :: IO Foo
myfoo = Foo <$> getEnvInt "someX" <*> getEnvText "someY"
問題
レコード フィールド名を明示的に書き出すことで構築したい場合はどうすればよいでしょうか? そのような:
myfoo = Foo { x = getEnvInt "someX", y = getEnvText "someY" }
これは型チェックしません。1つの解決策は
{-# LANGUAGE RecordWildCards #-}
myfoo = do
x <- getEnvInt "someX"
y <- getEnvText "someY"
return $ Foo {..}
これは悪くありません。しかし、(この時点ではそれ自体のためだけに)次のことが機能するかどうか疑問に思います。
data FooC f = FooC { x :: f Int, y :: f Text }
type Foo = FooC Maybe
myfoo :: IO Foo
myfoo = genericsMagic $ FooC
{ x = someEnvInt "someX"
, y = someEnvText "someY"
}
ベア パターン マッチングで実行できると思いますが、それではGHC.Generics
型の安全性が確保されないため、より強力なアプローチを探していました。generics-sop
レコードを異種リストに変換し、一見便利なhsequence
操作が付属しているに遭遇しました。
行き詰まったポイント
generics-sop
Applicative の型を異種リストの別の型パラメーターに格納しますI
。生成された変換を使用する場合、それは常に (Identity) です。したがって、hlist をマップし、エレメントから を削除する必要がありますI
。これにより、ApplicativeI
が上記の型パラメーター ( になりますComp IO Maybe
) に効果的に移動します。 .hsequence
I
しかし、削除/追加関数の型署名を記述する方法がわかりませんI
。これは、それぞれの hlist 要素の型が外側の型を失う/獲得することによって一貫して変化することを伝えます。これは可能ですか?