Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中表示typeclass的任意实现_Haskell_Typeclass - Fatal编程技术网

在Haskell中表示typeclass的任意实现

在Haskell中表示typeclass的任意实现,haskell,typeclass,Haskell,Typeclass,我正在努力克服多年来在经典Java风格继承模型中的工作,以真正熟悉Haskell。事情进展不顺利,我需要一些帮助 假设我有一个typeclassFoo。我想表示一个任意实现类的列表Foo,但不能限制列表中的每一项都是相同的;我需要一个异构的、开放的类型,以便我的库的使用者能够实现他们自己的Foo 原因是因为我想写以下内容(pidgin Haskell): 我如何创建一个可扩展的typeclass(或其他数据类型),它可以与相同typeclass的其他数据类型自由混合,但不一定是相同的确切类型?您

我正在努力克服多年来在经典Java风格继承模型中的工作,以真正熟悉Haskell。事情进展不顺利,我需要一些帮助

假设我有一个typeclass
Foo
。我想表示一个任意实现类的列表
Foo
,但不能限制列表中的每一项都是相同的;我需要一个异构的、开放的类型,以便我的库的使用者能够实现他们自己的
Foo

原因是因为我想写以下内容(pidgin Haskell):

我如何创建一个可扩展的typeclass(或其他数据类型),它可以与相同typeclass的其他数据类型自由混合,但不一定是相同的确切类型?

您正在寻找的是

IMHO最好的方法是使用存在主义,如维基上所述:

{-# LANGUAGE ExistentialQuantification #-}

data Showable = forall a . Show a => MkShowable a

pack :: Show a => a -> Showable
pack = MkShowable

hlist :: [Showable]
hlist = [ pack 3
        , pack 'x'
        , pack pi
        , pack "string"
        , pack (Just ()) ]

您尝试(异构)收集的问题在于:一旦您有了
Foo
列表,就很难回到原始类型。但是,如果您乐于忘记原始类型,另一种解决问题的方法是将数据转换为
Foo
。这种方法可能看起来是错误的,但请记住,数据在Haskell中是不可变的,因此无论如何您都无法修改对象,因此您可以使用
Foo
s的唯一方法就是从对象中获取信息。因此,像
Foo
那样的真正
Bar
和像
Bar
版本那样的新
Foo
之间没有区别(同样,Haskell lazy,因此只有在需要时才会进行转换)

当您意识到这一点时,您甚至可以进一步替换
对象
,但只需替换一组函数(如@chi-link中所述)。您的代码变为

 data Foo = { saySomething :: String, saySomethingElse :: String }
 -- Haskell is lazzy, so saySomething can be seen as function
 -- without argument

 class Fooable a where
       toFoo :: a -> Foo

 data Bar = Bar Int Char
 data Baz = Bar String

 instance Fooable Bar where
        toFoo (Bar i c) = { "Bar number : " ++ show i, "Bar char : " ++ [c] }
 instance Fooable Baz where
        toFoo (Baz s) = {"Your baz is " ++ s, "Nothing to add." }

 sayAll : [Foo] -> [String]
 sayAll = map saySomething

 bar = Bar 1 'a'
 baz = Baz "Bazzar"

 sayAll [toFoo bar, toFoo baz]

请注意,即使
somethingElse
看起来不像函数,但它只是一个普通函数,它永远不会被调用(在本例中)。
toFoo
的结果可以看作是
Bar
Foo
之间的桥梁这是一个-
[Showable]
[String]
之间没有实际区别,后者更简单。你是对的,但是如果typeclass提供了不止一个方法呢?事实上,我的观点不像卢克·帕尔默在他的博客中所表达的那样激进,但我确实认为他有道理。存在类型类模式在某些情况下很有用,但很容易被滥用。在
Foo
上会有多个方法。感谢@utdemir提供的答案,@chi提供了Luke Palmer文章的链接,因为一旦我了解了概念,我可能会重写我的代码。可扩展类型类是什么意思?类型类定义了一个类。例如
类Eq a,其中(==),(/=)::a->a->Bool
意味着
Eq
的实例类型必须实现
(==)
(/=)
。这是为了确保他们会有这些行动。我不明白你的意思。
 data Foo = { saySomething :: String, saySomethingElse :: String }
 -- Haskell is lazzy, so saySomething can be seen as function
 -- without argument

 class Fooable a where
       toFoo :: a -> Foo

 data Bar = Bar Int Char
 data Baz = Bar String

 instance Fooable Bar where
        toFoo (Bar i c) = { "Bar number : " ++ show i, "Bar char : " ++ [c] }
 instance Fooable Baz where
        toFoo (Baz s) = {"Your baz is " ++ s, "Nothing to add." }

 sayAll : [Foo] -> [String]
 sayAll = map saySomething

 bar = Bar 1 'a'
 baz = Baz "Bazzar"

 sayAll [toFoo bar, toFoo baz]