繁体   English   中英

克服Haskell中多态类型的限制

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM