【发布时间】:2015-11-07 19:13:06
【问题描述】:
我想建立一个具有一个共同属性的不同事物的列表,即它们可以变成字符串。面向对象的方法很简单:定义接口Showable 并让感兴趣的类实现它。当您无法更改类时,第二点原则上可能是一个问题,但让我们假设情况并非如此。然后你创建一个Showables 的列表,并用这些类的对象填充它,没有任何额外的噪音(例如,向上转换通常是隐式完成的)。 Java 中的概念证明is given here。
我的问题是我在 Haskell 中有哪些选项?下面我将讨论我尝试过但并不真正让我满意的方法。
方法 1:存在主义。有效但丑陋。
{-# LANGUAGE ExistentialQuantification #-}
data Showable = forall a. Show a => Sh a
aList :: [Showable]
aList = [Sh (1 :: Int), Sh "abc"]
对我来说,这里的主要缺点是在填写列表时需要Sh。这非常类似于在 OO 语言中隐式完成的向上转换操作。
更一般地说,已经在语言中的东西的虚拟包装器Showable - Show 类型类 - 在我的代码中增加了额外的噪音。不好。
方法 2:谓语。想要但不起作用。
对我来说,最直接的类型和我真正想要的是:
{-# LANGUAGE ImpredicativeTypes #-}
aList :: [forall a. Show a => a]
aList = [(1 :: Int), "abc"]
除此之外 (as I heard)ImpredicativeTypes 是“最好的情况是脆弱的,最坏的情况是破碎的”
它不编译:
Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
a type expected by the context: Show a => a
"abc" 也出现同样的错误。 (注意类型签名 1:没有它我会收到更奇怪的消息:Could not deduce (Num a) arising from the literal ‘1’)。
方法 3:Rank-N 类型以及某种功能列表(差异列表?)。
比起有问题的ImpredicativeTypes,人们可能更喜欢更稳定和被广泛接受的RankNTypes。这基本上意味着:移动
需要将类型构造函数(即[])之外的forall a. Show a => a 转换为普通函数类型。因此,我们需要将列表表示为普通函数。我几乎没有听说有这样的陈述。我听说的一个是差异列表。但是在Dlist package 中,主要类型是好旧的data,所以我们回到表语。我没有进一步研究这一行,因为我怀疑它可能会产生比方法 1 更冗长的代码。但如果你认为不会,请给我一个例子。
底线:你将如何在 Haskell 中完成这样的任务?您能否提供比 OO 语言更简洁的解决方案(尤其是代替填写列表 - 请参阅方法 1 中的代码注释)?您能否评论一下上面列出的方法的相关性?
UPD(基于第一个 cmets):为了便于阅读,这个问题当然被简化了。真正的问题更多是关于如何存储共享相同类型类的东西,即以后可以通过多种方式处理(Show 只有一种方法,但其他类可以有不止一种)。这会排除建议在填写列表时应用show 方法的解决方案。
【问题讨论】:
-
Java 和 Haskell 之间有一个您缺少的关键区别。在 Java 中,类型信息在向上转换时不会丢失,因此您可以再次向下转换并在以后执行其他有用的非
Stringy 事情(条件是选择正确的向下转换类型)。在 Haskell 中,一旦你向上转换,类型信息就会丢失并且你不能再次向下转换。因此,您不妨只拥有Strings 的列表。另请参阅Dynamic,它提供了比“justString”更丰富的界面。 -
我不太喜欢这个问题的标题。它声称语言/范式之间存在冲突,可能会呼吁一方的人们参加语言战争。
-
这是一个已知的反模式,也在Luke Palmer's blog 中讨论过。虽然我并不完全同意整篇博文,但我相信他提出的基本观点是扎实的。
-
从热门网络问题优化的标题中,我准备好以基于意见的方式投票结束。我对问题的质量感到惊喜,但是一旦你 15 分钟的 HNQ 结束,尝试将标题更改为不太可能吸引错误答案的名称。
-
对于它的价值,您的第二次尝试(使用禁言类型)与第一次不同,绝对不是您想要的。
[forall a. Show a => a]是forall a. Show a => a的居民列表。这种类型的居民只有一个——底部。没有其他可能的值可以成为调用者要求的 anyShow。没有 Int 可以容纳那种类型,没有 String ......什么都没有。从字面上看,这与您最初想要的相反。你可能想要[exists a. Show a => a],或者,skolemized,[(forall a. Show a => a -> r) -> r]。
标签: haskell