ian*_*675 6 generics haskell ghc ghci
我一直试图对数据类型进行一些抽象,我遇到了GHC的泛型的情况似乎有点奇怪.这是我的基本声明集:
class GFields f where
gfields :: f a -> [String]
instance (GFields c) => GFields (D1 i c) where
gfields = gfields . unM1
instance (GFields fs) => GFields (C1 i fs) where
gfields = gfields . unM1
instance (GFields f, GFields fs) => GFields (f :*: fs) where
gfields (f :*: fs) = gfields f ++ gfields fs
instance (Selector s) => GFields (S1 s r) where
gfields = (:[]) . selName
data Thing = Thing { foo :: String, bar :: Int }
deriving (Generic)
Run Code Online (Sandbox Code Playgroud)
Prelude.undefined如果我给它一个未定义的值,试图在GHCi中使用它给我:
> gfields $ from (undefined :: Thing)
*** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试手动运行一些预期的实例(只抓一个字段),我会得到我所期望的:
> selName $ (\(l :*: r) -> l) $ unM1 $ unM1 $ from (undefined :: Thing)
"foo"
Run Code Online (Sandbox Code Playgroud)
我为什么要Prelude.undefined进入另一个而不进入另一个?
所以这很有趣,你所拥有的实际上并不完全是所做的,内联后的实际代码是
main = print
. (\(l :*: r) -> selName l ++ selName r)
. unM1
. unM1
. from
$ (undefined :: Thing)
Run Code Online (Sandbox Code Playgroud)
但是,更改\(l :*: r) -> selName l ++ selName r 为您所拥有的不会崩溃。所以差异很明显就在这一行。右场有问题的明显想法很快就被证明是错误的,因为\(l :*: r) -> r仍然运行。
我们可以看到,唯一的非底部结果的形式是(\l :*: r -> ???)??? 是l或r。没有其他的。
那么让我们看一下 的派生实例-ddump-deriv。
from (Thing g1_atM g2_atN) = M1 (M1 (M1 (K1 g1_atM) :*: M1 (K1 g2_atN)))
Run Code Online (Sandbox Code Playgroud)
请注意,这在构造函数中是严格的。所以我们一定不能对结果要求太严格,from undefined否则代码会崩溃。所以现在我们有点像在纸牌屋上行走,因为强制执行任何部分都会使我们的程序崩溃。有趣的是
-- The derived selectors
instance Selector S1_0_0Thing where
selName _ = "foo"
instance Selector S1_0_1Thing where
selName _ = "bar"
Run Code Online (Sandbox Code Playgroud)
它的论证并不严格。所以这里有一个问题,你的代码全部编译为常量,"foo"因为selName是常量,我们不使用任何先前的计算;这是编译时计算。l然而,如果我们使用和在该 lambda 中进行任何类型的计算r,那么当我们使用selName或执行任何操作来查看结果时,我们会强制 lambda 运行,但由于l :*: r实际上是底部,所以我们会崩溃。
作为一个快速演示,这会崩溃
main = (`seq` putStrLn "Crashes")
. (\(l :*: r) -> ())
. unM1
. unM1
. from
$ (undefined :: Thing)
Run Code Online (Sandbox Code Playgroud)
但这不会
main = (const $ putStrLn "Crashes")
. (\(l :*: r) -> ())
. unM1
. unM1
. from
$ (undefined :: Thing)
Run Code Online (Sandbox Code Playgroud)
TLDR,只需使每个字段未定义,但顶层构造函数不应该位于底层。
| 归档时间: |
|
| 查看次数: |
186 次 |
| 最近记录: |