本文介绍了没有存在类型的异构索引结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建异构索引结构,并提出了以下解决方案,但。

你能看到更好的解决方案吗?

>

我想保持接口定义( type 和 class )和具体实现( data 和 instance )。 编辑后面的@ hammar的评论:在实际应用中,值不是 Show n,而只是存储查询;另外 myData 对于其他记录来说更为复杂。如果这可能导致更好的解决方案,那么确切的要求是建立地图(内部地图)的地图。每个内部映射都是同类的,并且以映射字符串a 的形式,但是每个内部映射可以为其值执行不同的类型。您也可以将其视为两级索引结构。这个实现不必使用 Data.Map ,但必须是有效的。

  { - #语言ExistentialQuantification# - } 
模块Scratch.SO_ExtistentialTypes其中

进口Data.Map

数据HeteroValue = FORALL一个。显示a => HV a

实例显示HeteroValue其中
显示(HV b)=显示b

类型MyMap = Map String HeteroValue

class MyClass c其中
getMyMap :: c - > MyMap

MyData = MyData {
myMap :: MyMap
}

实例MyClass MyData其中
getMyMap = myMap

这段代码可以使用ghci运行

  let myMap = fromList [(key1,HVabc),(key2,HV 123)] :: MyMap 
let myData = MyData myMap $ b $ getMyMap myData


解决方案

href =http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Dynamic.html =nofollow> Data.Dynamic 。

 模块Scratch.SO_Dyn其中

导入Data.Dynamic
导入Data.Map

type MyMap = Map String Dynamic

class MyClass c其中
getMyMap :: c - > MyMap

MyData = MyData {
myMap :: MyMap
}

实例MyClass MyData其中
getMyMap = myMap

您要放入此映射的数据必须派生Typeable。

使用 { - #LANGUAGE DeriveDataTypeable# - } 和派生(Data,Typeable),
另请参阅。

然后,您可以将数据转换为 Dynamic 键入 toDyn ,并安全地将它从动态类型转换为 fromDynamic 。






虽然这是一个非常有效的方法,但我和其他Haskellers会强烈建议您考虑制作自定义数据类型,而不是诉诸于真正异构的集合。假设(本着万圣节的精神),你知道一个事实,即你将要放入这张地图的唯一事物是 Cat s,女巫 es和 Ghoul s。

 数据Cat = ... 
data Witch = ...
data Ghoul = ...

通过简单标记每个可能的选项,您可以稍后确定每件事情。

 数据HeteroValue 
= DarkOmen Cat
|哈格女巫
| Haunting食尸鬼

案例(Map.lookup午夜访客的地图)
Just(DarkOmen猫) - >嘘猫
Just(Hag witch) - > cuckle witch
Just(萦绕食尸鬼) - > spook ghoul
Nothing - >错误...


I am trying to build an heterogeneous indexed structure and came up with the following solution but I was told not to use existential types.

Can you see a better solution ?

I would like to keep the separation between the definition of the interfaces (the type and class) and the concrete implementation (the dataand instance). Edit following @hammar's comment: in the real application, values are not Shown but simply stored an queried; also myDatais more complex with additional records.

If this can lead to a better solution, the exact requirement is to build a map of maps (the inner maps). Each inner map is homogeneous and in the form of Map String a however each inner map may enforce a different type for its values. You may also think of it as a two level indexed structure. The implementation does not have to use a Data.Map but must be efficient.

{-# LANGUAGE ExistentialQuantification #-}
module Scratch.SO_ExtistentialTypes where

import Data.Map

data HeteroValue = forall a. Show a => HV a

instance Show HeteroValue where
    show (HV b) = show b

type MyMap = Map String HeteroValue

class MyClass c where
    getMyMap :: c -> MyMap

data MyData = MyData {
    myMap ::  MyMap
}

instance MyClass MyData where
    getMyMap = myMap

This snippet can be run using ghci

let myMap = fromList [("key1", HV "abc"), ("key2", HV 123)] :: MyMap
let myData = MyData myMap
getMyMap myData
解决方案

One way to do "heterogeneous collections" is with Data.Dynamic.

module Scratch.SO_Dyn where

import Data.Dynamic
import Data.Map

type MyMap = Map String Dynamic

class MyClass c where
    getMyMap :: c -> MyMap

data MyData = MyData {
    myMap ::  MyMap
}

instance MyClass MyData where
    getMyMap = myMap

The data you wish to put into this map must derive Typeable.
Use {-# LANGUAGE DeriveDataTypeable #-} and deriving (Data, Typeable),see also http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/deriving.html#deriving-typeable.

You can then cast your data to the Dynamic type with toDyn, and safely cast it from the Dynamic type with fromDynamic.


Although this is a perfectly valid approach, I and many other Haskellers would highly recommend that you consider making a custom data type rather than resorting to a truly heterogeneous collection. Suppose (in the spirit of Halloween) that you know for a fact that the only sorts of things you will put into this map are Cats, Witches, and Ghouls.

data Cat = ...
data Witch = ...
data Ghoul = ...

By simply tagging each possible option, you can later determine what each thing is.

data HeteroValue
  = DarkOmen Cat
  | Hag Witch
  | Haunting Ghoul

case (Map.lookup "Midnight visitor" theMap) of
  Just (DarkOmen cat) -> hiss cat
  Just (Hag witch) -> cackle witch
  Just (Haunting ghoul) -> spook ghoul
  Nothing -> error ...

这篇关于没有存在类型的异构索引结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 12:20
查看更多