例如:
data Foo = Bar Int | Baz String
我想使用如下功能:
qux :: [Foo] -> [Baz]
qux fs = filter f fs
where
f (Baz _) = True
f _ = False
通常,我需要:
data Bar = Bar Int
data Baz = Baz String
data Foo = FBar Bar | FBaz Baz
qux = ...
但我对这个解决方案并不满意,因为它需要大量冗余代码。
有没有一种优雅的方法来解决这个问题?
最佳答案
一种可能性是使用 GADTs 。其要点是,这使我们能够拥有所谓的 "phantom" type argument到数据类型定义。我们可以用它做的一件事是限制使用此数据类型的函数(例如)的类型,以便它仅适用于可由特定构造函数创建的值。
以下是我如何编写您以这种风格提供的示例(注意:您需要启用 GADTs 扩展):
{-# LANGUAGE GADTs #-}
data BarType -- Note: These could be called Bar and Baz, but I named them this for clarity
data BazType
data Foo a where
Bar :: Int -> Foo BarType
Baz :: Int -> Foo BazType
有了这个,你可以编写这样的函数:
onlyAcceptsBars :: Foo BarType -> Int
onlyAcceptsBars (Bar bar) = -- ...
-- There would be a compile-time error if you had a case like this:
-- onlyAcceptsBars (Baz baz) = ...
onlyAcceptsBazs :: Foo BazType -> Int
onlyAcceptsBazs (Baz baz) = -- ...
acceptsAnyFoo :: Foo a -> Int
acceptsAnyFoo (Bar bar) = -- ...
acceptsAnyFoo (Baz baz) = -- ...
关于haskell - 有没有办法将一种类型的构造函数也用作类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20530801/