[英]Overcoming limitation with polymorphic type in haskell
我有这样的类型
data AgentSpec a = AgentSpec
{ agent :: a
, events :: [ByteString]
} deriving (Show)
和其他类似的类型
data Java = Java
data Php = Php
我正在尝试创建一个类型的函数,
allEvents :: [AgentSpec a] -> [ByteString]
allEvents aspec = concatMap events aspec
但是我无法创建[AgentSpec a]
类型的值
如果我做,
allEvents [AgentSpec Java ["event1, "event2"], AgentSpec Php ["event3, "event4"]]
它不进行类型检查,并且可以理解的是。 它不键入检查,因为, AgentSpec Java
不是AgentSpec a
所以我明白为什么它不起作用。 但是我不知道如何在不编写大量重复代码的情况下克服这一限制。
一种替代方法是手动构造类型列表,
allEvents :: [ByteString]
allEvents = ["event1", "event2", "event3", "event4"].
但是我觉得我只是在重写已经在类型中建模的东西。 有什么办法可以利用我现有的类型来获得我想要的东西吗? 这只是所有AgentSpec字节串的串联列表
这段代码:
allEvents [AgentSpec Java ["event1, "event2"], AgentSpec Php ["event3, "event4"]]
无法编译,因为AgentSpec Java ["event1, "event2"]
和AgentSpec Php ["event3", "event4"]
具有不同的类型,并且Haskell中的列表只能包含一种类型AgentSpec a [ByteString]
可以是为任何类型a
创建a
,但一旦创建就不能与其他类型的值混合。
我不知道您在建模什么,但是通常我会建议这样的事情:
data Language = Java | Php
data AgentSpec = AgentSpec
{ agent :: Language
, events :: [ByteString]
} deriving (Show)
allEvents = [AgentSpec Java ["event1", "event2"], AgentSpec Php ["event3", "event4"]]
但是,根据您对编写库的评论,听起来并不可行。 您能详细说明您要达到的目标吗?
Haskell中有一些实现异构列表的技术。 您可以做的一件事是:
{-# LANGUAGE GADTs #-}
data SomeAgentSpec where
SAS :: AgentSpec a -> SomeAgentSpec
allEvents :: [SomeAgentSpec] -> [ByteString]
allEvents aspec = concatMap ev aspec
where ev (SAS a) = events a
然后,
\> let a = AgentSpec Java ["1.", "java"]
\> let b = AgentSpec Php ["2.", "php" ]
\> allEvents [SAS a, SAS b]
["1.","java","2.","php"]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.