在具有类型系列扩展的Haskell中,这是完全合法的(ideone):
{-# LANGUAGE TypeFamilies #-}
type family F a
data A = A Int
data B = B Double
type instance F A = Int
type instance F B = Double
class Get a where
get :: a -> F a
instance Get A where
get (A x) = x
instance Get B where
get (B x) = x
main = print $ (get (A 3), get (B 2.0))
基本上我已经定义了两个函数get
。
具有类型签名的人:
get :: A -> Int
第二个:
get :: B -> Double
然而,上面的代码中有很多错误。我希望能够做到的是:
get :: A -> Int
get (A x) = x
get :: B -> Double
get (B x) = x
我理解使用这种语法完全不起作用,但有没有办法可以得到我想要实现的目标而没有十几行定义类型实例和类实例?考虑到第一个代码工作正常,我认为没有理由为什么Haskell编译器不能将这个更短的代码转换成上面的代码。
答案 0 :(得分:3)
这应该做的工作:
class Get a b | a -> b where
get :: a -> b
instance Get A Int where
...
https://www.haskell.org/haskellwiki/Functional_dependencies
好的,所以它只能摆脱类型家庭。我不认为你可以摆脱类型类,因为它们是实现重载的 方法。此外,如果没有类,您将无法在类型中表达类约束,例如你不能写这个:
getPaired :: (Get a b, Get c d) => (a, c) -> (b, d)
答案 1 :(得分:2)
我不知道这是否适用于您的用例 - 您的示例是相当人为的。但是你可以在这里使用GADT代替类型:
data T a where
A :: Int -> T Int
B :: Double -> T Double
get :: T a -> a
get (A x) = x
get (B x) = x
通常,没有办法让编译器猜出你想要写的代码并为你编写代码。我怀疑,这样的编译器会淘汰大多数程序员,所以我们都应该感到高兴它不存在。我确实同意你写的很多东西要做的很少,但也许这表明你的代码有问题,而不是编译器中的缺陷。
答案 2 :(得分:1)
这是另一种选择:
{-# LANGUAGE TypeFamilies #-}
data A = A Int
data B = B Double
class Get a where
type F a
get :: a -> F a
instance Get A where
type F A = Int
get (A x) = x
instance Get B where
type F B = Double
get (B x) = x
main = print (get (A 3), get (B 2.0))
对我来说,它看起来比功能依赖更好。 所有内容都在https://www.haskell.org/haskellwiki/GHC/Type_families
中描述