Haskell中记录类型和子类型的当前状态是什么?
我知道有一个关于事情做过类似超载记录名称等具体工作了,我想提出三个不同的记录类型A,B以及C在那里B并C包含所有相同的字段标签作为A,但不分享彼此的字段标签.然后,我希望能写的功能,其中f : A -> int,g: B -> int,h: C -> int其中功能f还接受带有类型的参数B和C.基本上,我想要B和C成为亚型A.更具体地说,如果我不必重复所有的字段标签,那就太好了.在伪代码中,这就像
data A = A { a :: String }
data B = B { A, b :: Char }
data C = C { C, c :: Float }
f :: A/B/C -> int
g :: B -> int
h :: C -> int
Run Code Online (Sandbox Code Playgroud)
没有一个.有一个建议添加重载记录字段和一个工作实现,但AFAIK还没有合并到GHC的头部.您可以在此处阅读该提案.一旦它落地,我们将有类似于rho多态的东西,但自动生成/推断类型类.请注意,这不是子类型.{a :: Int, b :: Bool} <: {a :: Int}在Haskell中不是一个概念,而是我们能够说出类似的东西
foo :: r {a :: Int} -> Int
foo = a
Run Code Online (Sandbox Code Playgroud)
这真的会更像
foo :: Has "a" Int r => r -> Int
foo = a
Run Code Online (Sandbox Code Playgroud)
相反,我们写了类似的东西
foo :: {a :: Int} -> {a :: Int}
foo = id
Run Code Online (Sandbox Code Playgroud)
并希望这表现得像我们的子类型,我们可以做类似的事情
foo _ = A {a = 1}
Run Code Online (Sandbox Code Playgroud)
并返回任何类型的子类型{a :: Int}.
库存有其他选择,如乙烯基,在某种程度上还有镜头.我建议现在调查这些,特别是如果你想要与7.6/7.8兼容.
有几种不同的方法来实现这一点以及一些缺点.
以下是我正在使用的类型:
data A = A { a :: String}
data B = B { bA :: A, b :: Char}
data C = C { cA :: A, c :: Float}
Run Code Online (Sandbox Code Playgroud)
您可以定义f一些的方法CanF类A,B和C所有的实例:
class CanF a where
f :: a -> Int
instance CanF A where
f = length . a
instance CanF B where
f = f . bA
instance CanF C where
f = f . cA
Run Code Online (Sandbox Code Playgroud)
根据实例定义B和C实例A清楚地表明f在每种情况下做同样的事情.f根据定义F实例的类型,很容易做出不同的事情.这种方法的缺点是需要添加任何其他类似f的函数作为相同"CanSomething"类的方法.
main :: IO ()
main = do
print (f a)
print (f b)
print (f c)
where
a = A "Hello"
b = B a 'H'
c = C a 3.14
Run Code Online (Sandbox Code Playgroud)
另一种方法是编写f一个由一个总是给你一个类的类约束的函数A.
class RepA a where
getA :: a -> A
instance RepA A where
getA = id
instance RepA B where
getA = bA
instance RepA C where
getA = cA
f :: RepA a => a -> Int
f = length . a . getA
Run Code Online (Sandbox Code Playgroud)
在这里,您没有灵活性来定义f可以做什么,哪些可能好或坏.优点是您可以定义其他功能,A而不需要为您的类添加新方法.
处理此问题的首选方法是记录功能方法.定义一个参数化数据类型,其中包含要调用的函数.然后为您的记录类型定义专门的构造函数.这种方法的缺点是它通常更冗长.优点是您可以通过提供不同F的f功能来换出行为.另一个优点是您无需语言扩展即可完成更多任务.
data F a = F { f :: a -> Int }
af :: F A
af = F $ length . a
bf :: F B
bf = F $ f af . bA
cf :: F C
cf = F $ f af . cA
main :: IO ()
main = do
print (f af a)
print (f bf b)
print (f cf c)
where
a = A "Hello"
b = B a 'H'
c = C a 3.14
Run Code Online (Sandbox Code Playgroud)