gpt4 book ai didi

generics - GHC 泛型行为在 GHCi 中似乎有所不同

转载 作者:行者123 更新时间:2023-12-03 06:22:33 25 4
gpt4 key购买 nike

我一直在尝试对数据类型进行一些抽象,并且遇到了 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)

如果我给它一个未定义的值,尝试在 GHCi 中使用它会给我 Prelude.undefined :

> gfields $ from (undefined :: Thing)
*** Exception: Prelude.undefined

但是,如果我尝试手动运行一些预期的实例(仅抓取一个字段),我会得到我所期望的结果:

> selName $ (\(l :*: r) -> l) $ unM1 $ unM1 $ from (undefined :: Thing)
"foo"

为什么我在其中一个中得到 Prelude.undefined,而在另一个中却没有?

最佳答案

所以这很有趣,你所拥有的实际上并不完全是完成的,内联后的实际代码是

main = print
. (\(l :*: r) -> selName l ++ selName r)
. unM1
. unM1
. from
$ (undefined :: Thing)

但是,将 \(l :*: r) -> selName l++ selName r 更改为您所拥有的内容不会崩溃。所以差异很明显就在这一行。由于 \(l :*: r) -> r 仍然运行,因此右字段有问题的明显想法很快就被覆盖了。

我们可以看到唯一的非底部结果的形式为 (\l :*: r -> ???) 其中 ???是 lr。没有别的了。

那么让我们看一下使用 -ddump-deriv 派生的实例。

from (Thing g1_atM g2_atN) = M1 (M1 (M1 (K1 g1_atM) :*: M1 (K1 g2_atN)))

请注意,这在构造函数中是严格的。所以我们不能对from undefined的结果太严格,因为代码会崩溃。所以现在我们有点像在纸牌屋上行走,因为强制执行任何部分都会使我们的程序崩溃。有趣的是

-- The derived selectors
instance Selector S1_0_0Thing where
selName _ = "foo"

instance Selector S1_0_1Thing where
selName _ = "bar"

它的论证并不严格。所以这里有一个问题,您的代码全部编译为常量 "foo" 因为 selName 是常量,我们不使用任何先前的计算;这是编译时计算。但是,如果我们在该 lambda 中使用 lr 进行任何类型的计算,那么当我们使用 selName 或执行任何操作来查看结果时,我们强制 lambda 运行,但由于 l :*: r 确实位于底部,所以我们崩溃了。

作为一个快速演示,这会崩溃

main = (`seq` putStrLn "Crashes")
. (\(l :*: r) -> ())
. unM1
. unM1
. from
$ (undefined :: Thing)

但这不会

main = (const $ putStrLn "Crashes")
. (\(l :*: r) -> ())
. unM1
. unM1
. from
$ (undefined :: Thing)

TLDR,只需将每个字段设为未定义即可,但顶层构造函数不应该位于底层。

关于generics - GHC 泛型行为在 GHCi 中似乎有所不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19917285/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com