gpt4 book ai didi

haskell - 为什么我不能使用类型 `Show a => [Something -> a]` ?

转载 作者:行者123 更新时间:2023-12-02 15:27:14 24 4
gpt4 key购买 nike

我有一个记录类型

data Rec {
recNumber :: Int
, recName :: String
-- more fields of various types
}

我想为 Rec 编写一个 toString 函数:

recToString :: Rec -> String
recToString r = intercalate "\t" $ map ($ r) fields
where fields = [show . recNumber, show . recName]

这有效。 fields 的类型为 [Rec -> String]。但我很懒,我更喜欢写作

recToString r = intercalate "\t" $ map (\f -> show $ f r) fields
where fields = [recNumber, recName]

但这行不通。直觉上我会说 fields 的类型为 Show a => [Rec -> a] ,这应该没问题。但 Haskell 不允许这样做。

我想了解这里发生了什么。如果我说在第一种情况下我得到一个函数列表,这样 show 的 2 个实例实际上不是同一个函数,但 Haskell 能够在编译时确定哪个是哪个(这就是为什么它可以),我是对的吗)。

[show . recNumber, show . recName]
^-- This is show in instance Show Number
^-- This is show in instance Show String

而在第二种情况下,我在代码中只有一次 show 的文字使用,并且必须引用多个实例,而不是在编译时确定?

map (\f -> show $ f r) fields
^-- Must be both instances at the same time

有人可以帮我理解这一点吗?还有是否有解决方法或类型系统扩展可以实现这一点?

最佳答案

类型签名并没有表达您所认为的内容。

这似乎是一个常见的误解。考虑函数

foo :: Show a => Rec -> a

人们似乎经常认为这意味着“foo 可以返回它想要的任何类型,只要该类型支持 Show”。 事实并非如此。

实际上的意思是foo必须能够返回任何可能的类型,因为调用者可以选择返回类型。

稍微思考一下就会发现 foo 实际上不可能存在。无法将 Rec 转换为任何可能存在的类型。这是不可能的。

人们经常尝试使用 Show a => [a] 来表示“混合类型的列表,但它们都有 Show”。这显然是行不通的;这种类型实际上意味着列表元素可以是任何类型,但它们仍然必须完全相同。

你想做的事情似乎很合理。不幸的是,我认为你的第一个例子已经尽可能接近了。您可以尝试使用元组和透镜来解决这个问题。您可以尝试使用Template Haskell。但除非你有很多领域,否则可能根本不值得付出努力。

关于haskell - 为什么我不能使用类型 `Show a => [Something -> a]` ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28679185/

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