简体   繁体   English

克服Haskell中多态类型的限制

[英]Overcoming limitation with polymorphic type in haskell

I have a type like so, 我有这样的类型

data AgentSpec a = AgentSpec 
                     { agent :: a
                     , events :: [ByteString] 
                     } deriving (Show)

and other types like so, 和其他类似的类型

data Java = Java
data Php = Php

I am trying to create a function of type, 我正在尝试创建一个类型的函数,

allEvents :: [AgentSpec a] -> [ByteString]
allEvents aspec = concatMap events aspec

But I am unable to create values of type [AgentSpec a] 但是我无法创建[AgentSpec a]类型的值

If I do, 如果我做,

allEvents [AgentSpec Java ["event1, "event2"], AgentSpec Php ["event3, "event4"]]

it does not typecheck and understandably so. 它不进行类型检查,并且可以理解的是。 It doesn't type check because, AgentSpec Java is not AgentSpec a 它不键入检查,因为, AgentSpec Java不是AgentSpec a

So I understand why it does not work. 所以我明白为什么它不起作用。 But I do not know how to overcome this limitation without writing a lot of duplicate code. 但是我不知道如何在不编写大量重复代码的情况下克服这一限制。

One alternatve is to manually construct a list of type, 一种替代方法是手动构造类型列表,

allEvents :: [ByteString]
allEvents = ["event1", "event2", "event3", "event4"].

But I feel like I'm simply rewriting things I've already modelled in my types. 但是我觉得我只是在重写已经在类型中建模的东西。 Is there any way to make use of my existing types to get what I want? 有什么办法可以利用我现有的类型来获得我想要的东西吗? Which is just a concatenated list of bytestrings of all the AgentSpecs 这只是所有AgentSpec字节串的串联列表

This code: 这段代码:

allEvents [AgentSpec Java ["event1, "event2"], AgentSpec Php ["event3, "event4"]]

doesn't compile because AgentSpec Java ["event1, "event2"] and AgentSpec Php ["event3", "event4"] are of different types, and lists in Haskell can only contain one type. An AgentSpec a [ByteString] can be created for any type a , but once created it can't be mixed with values of a different type. 无法编译,因为AgentSpec Java ["event1, "event2"]AgentSpec Php ["event3", "event4"]具有不同的类型,并且Haskell中的列表只能包含一种类型AgentSpec a [ByteString]可以是为任何类型a创建a ,但一旦创建就不能与其他类型的值混合。

I don't know what exactly you're modeling, but typically I'd recommend something like this: 我不知道您在建模什么,但是通常我会建议这样的事情:

data Language = Java | Php

data AgentSpec = AgentSpec 
                     { agent :: Language
                     , events :: [ByteString] 
                     } deriving (Show)

allEvents = [AgentSpec Java ["event1", "event2"], AgentSpec Php ["event3", "event4"]]

Based on your comment about writing a library, though, it doesn't sound like this would work. 但是,根据您对编写库的评论,听起来并不可行。 Can you elaborate on what you're trying to achieve? 您能详细说明您要达到的目标吗?

There are some techniques to implement heterogenous lists in Haskell . Haskell中有一些实现异构列表的技术。 One thing you can do is: 您可以做的一件事是:

{-# LANGUAGE GADTs #-}

data SomeAgentSpec where
    SAS :: AgentSpec a -> SomeAgentSpec

allEvents :: [SomeAgentSpec] -> [ByteString]
allEvents aspec = concatMap ev aspec
    where ev (SAS a) = events a

then, 然后,

\> 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