说,我想像这样定义一个记录属性:
data Attribute = Attribute {name :: String, value :: Any}
这当然不是有效的haskell代码.但是有一种类型'任何',基本上说任何类型都会这样做?或者是使用类型变量的唯一方法?
data Attribute a = Attribute {name :: String, value :: a}
bdo*_*lan 68
一般来说,Any类型不是很有用.考虑一下:如果你创建了一个可以容纳任何内容的多态列表,你可以对列表中的类型做些什么?答案当然不算什么 - 你不能保证这些元素有任何共同的操作.
通常做的是:
使用GADT创建一个可以包含特定类型类的元素的列表,如:
data FooWrap where
FooWrap :: Foo a => a -> FooWrap
type FooList = [FooWrap]
Run Code Online (Sandbox Code Playgroud)
使用这种方法,您不知道元素的具体类型,但是您知道可以使用Foo类型类的元素来操作它们.
创建一个类型以在列表中包含的特定具体类型之间切换:
data FooElem = ElemFoo Foo | ElemBar Bar
type FooList = [FooElem]
Run Code Online (Sandbox Code Playgroud)
这可以与方法1结合使用,以创建一个列表,该列表可以包含属于一组固定类型类的元素.
在某些情况下,构建操作函数列表会很有帮助:
type FooList = [Int -> IO ()]
Run Code Online (Sandbox Code Playgroud)
这对事件通知系统之类的东西很有用.在向列表添加元素时,将其绑定在一个函数中,该函数执行您稍后要执行的任何操作.
使用Data.Dynamic(不推荐!)作为作弊.但是,这并不能保证特定元素可以完全被操纵,因此上述方法应该是优选的.
Mik*_*kov 21
添加到bdonlan的答案:您也可以使用存在类型代替GADT :
{-# LANGUAGE ExistentialQuantification #-}
class Foo a where
foo :: a -> a
data AnyFoo = forall a. Foo a => AnyFoo a
instance Foo AnyFoo where
foo (AnyFoo a) = AnyFoo $ foo a
mapFoo :: [AnyFoo] -> [AnyFoo]
mapFoo = map foo
Run Code Online (Sandbox Code Playgroud)
这基本上等同于bdonlan的GADT解决方案,但不会强加您对数据结构的选择 - 您可以使用Map而不是列表,例如:
import qualified Data.Map as M
mFoo :: M.Map String AnyFoo
mFoo = M.fromList [("a", AnyFoo SomeFoo), ("b", AnyFoo SomeBar)]
Run Code Online (Sandbox Code Playgroud)
该data AnyFoo = forall a. Foo a => AnyFoo a位也可以用GADT表示法写成:
data AnyFoo where
AnyFoo :: Foo a => a -> AnyFoo
Run Code Online (Sandbox Code Playgroud)
Dan*_*ner 12
这听起来像一个非常基本的问题,所以我将提供比其他人更基本的答案.这几乎总是正确的解决方案:
data Attribute a = Attribute { name :: String, value :: a }
Run Code Online (Sandbox Code Playgroud)
然后,如果你想要一个包装an的属性Int,该属性将具有类型Attribute Int,或者包含a的属性Bool将具有类型Attribute Bool等.您可以使用任何类型的值创建这些属性; 例如,我们可以写
testAttr = Attribute { name = "this is only a test", value = Node 3 [] }
Run Code Online (Sandbox Code Playgroud)
创建类型的值Attribute (Tree Int).
| 归档时间: |
|
| 查看次数: |
7175 次 |
| 最近记录: |