语境
如果我们有
data Foo = Foo { x :: Maybe Int, y :: Maybe Text }
我们已经可以在 Applicative 上下文(这里是 IO)中构建它的 applicative-style
myfoo :: IO Foo
myfoo = Foo <$> getEnvInt "someX" <*> getEnvText "someY"
问题
如果一个人更喜欢明确写出记录字段名称怎么办?如:
myfoo = Foo { x = getEnvInt "someX", y = getEnvText "someY" }
这不会进行类型检查。一种解决方案是
{-# 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
I
将 Applicative 的类型存储在其异构列表的单独类型参数中,并且在使用生成的转换时始终为(Identity)。所以我需要映射 hlist 并I
从元素中删除 ,这将有效地将 Applicative 移动I
到提到的类型参数(它将是Comp IO Maybe
),所以我可以使用hsequence
,最后加回I
s 以便我可以隐蔽回记录.
但是我不知道如何为I
删除/添加函数编写类型签名,该函数表明各个 hlist 元素的类型通过丢失/获得外部类型而不断变化。这甚至可能吗?