haskell里有“任何”这个字吗?

7dl7o3gd  于 2023-02-16  发布在  其他
关注(0)|答案(6)|浏览(136)

比如,我想定义一个记录属性,如下所示:
data Attribute = Attribute {name :: String, value :: Any}
这当然不是有效的haskell代码。但是有没有一个类型'Any'基本上说任何类型都可以?或者使用类型变量是唯一的方法?
data Attribute a = Attribute {name :: String, value :: a}

euoag5mw

euoag5mw1#

一般来说,Any类型不是很有用。如果您创建了一个可以容纳任何内容的多态列表,那么您可以对列表中的类型做些什么呢?答案当然是什么也不做-您无法保证这些元素之间存在任何公共操作。
通常会做的是:
1.使用GADTs创建一个列表,该列表可以包含特定类型类的元素,如下所示:

data FooWrap where
    FooWrap :: Foo a => a -> FooWrap
type FooList = [FooWrap]

使用这种方法,您不知道元素的具体类型,但知道可以使用Foo类型类的元素来操作它们。
1.创建类型以在列表中包含的特定具体类型之间切换:

data FooElem = ElemFoo Foo | ElemBar Bar
type FooList = [FooElem]

这可以与方法1结合起来创建一个列表,该列表可以保存属于固定类型类集合之一的元素。
1.在某些情况下,构建一个操作函数列表会很有帮助:

type FooList = [Int -> IO ()]

这对于事件通知系统很有用,在向列表添加元素时,你可以将它绑定到一个函数中,这个函数可以执行你以后想要做的任何操作。
1.使用Data.Dynamic(不推荐!)作为一种欺骗手段。然而,这并不能保证一个特定的元素可以被操纵,因此以上方法应该是首选。

vyswwuz2

vyswwuz22#

博杜伦的回答中还补充了一点:除了GADT,您还可以使用existential types

{-# 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

这基本上等同于bdonlan的GADT解决方案,但不会强制您选择数据结构-您可以使用Map代替列表,例如:

import qualified Data.Map as M

mFoo :: M.Map String AnyFoo
mFoo = M.fromList [("a", AnyFoo SomeFoo), ("b", AnyFoo SomeBar)]

data AnyFoo = forall a. Foo a => AnyFoo a位也可以用GADT表示法写成:

data AnyFoo where
  AnyFoo :: Foo a => a -> AnyFoo
agxfikkp

agxfikkp3#

Data.Dynamic中有一个类型Dynamic,它可以容纳任何内容(当然,可以容纳Typeable中的任何内容),但这通常不是正确的方法,您要解决的问题是什么?

ffdz8vbo

ffdz8vbo4#

这听起来像是一个非常基本的问题,所以我会给予一个比任何人都更基本的答案。下面是几乎总是正确的答案:

data Attribute a = Attribute { name :: String, value :: a }

然后,如果需要 Package Int的属性,则该属性的类型应为Attribute Int, Package Bool的属性的类型应为Attribute Bool,以此类推。可以使用任何类型的值创建这些属性;比如我们可以写

testAttr = Attribute { name = "this is only a test", value = Node 3 [] }

来创建Attribute (Tree Int)类型的值。

ao218c7q

ao218c7q5#

如果你的数据最终需要成为一个特定的类型,你可以使用Convertible和GADT,因为作为消费者,你只对你需要消费的数据类型感兴趣。

{-# LANGUAGE GADTs #-}
import Data.Convertible 

data Conv b where 
   Conv ::  a -> (a -> b) -> Conv b
   Chain :: Conv b -> (b -> c) -> Conv c

unconv :: (Conv b) -> b 
unconv (Conv a f) = f a
unconv (Chain c f) = f $ unconv c

conv :: Convertible a b => a -> Conv b 
conv a = (Conv a convert)

totype :: Convertible b c => Conv b -> Conv c
totype a = Chain a convert

这不是很难推导出函子,共单元素和单子示例。我可以张贴他们,如果你有兴趣。

sycxhyv7

sycxhyv76#

丹尼尔·瓦格纳的回答是正确的:几乎在90%的情况下使用多态类型是你所需要的全部。2所有其他的回答对剩下的10%的情况都是有用的,但是如果你仍然没有很好的多态知识来问这个问题,那么理解GADT或存在类型将是极其复杂的......我的建议是“尽可能保持简单”。

相关问题