我在数据'D'中使用了类型族来约束其中第一项的类型。 现在我需要从一些常用函数(如intermediate_func)创建“D B1”或“D B2”类型的对象。但是下面的代码不起作用。 有什么建议怎么做?或以另一种方式施加类似的约束。
data A1 = A1
data A2 = A2
data B1 = B1
data B2 = B2
data C a b where
C1 :: Int → C a b
C2 :: Char → C A1 b
C3 :: Bool → C A1 B1
type family ResT b where
ResT B1 = C A1 B1
ResT B2 = C A2 B2
data D b where
D1 :: ResT B1 → C A1 B1 → D B1
D2 :: ResT b → C A1 b → D b
-- This does not compile
intermediate_func :: Int → D b
intermediate_func i = D2 (C1 i) (C1 i)
-- This works
-- intermediate_func :: Int -> D B2
-- intermediate_func i = D2 (C1 i) (C1 i)
-- So does this
-- intermediate_func :: Int -> D B1
-- intermediate_func i = D2 (C1 i) (C1 i)
答案 0 :(得分:2)
您需要证明b
是B1
或B2
,而不是其他任何内容。如上所述,可以调用intermediate_func :: Int → D String
。
您可以通过单身人士传递此类证据:
data S b where
SB1 :: S B1
SB2 :: S B2
intermediate_func :: S b → Int → D b
intermediate_func SB1 i = D2 (C1 i) (C1 i)
intermediate_func SB2 i = D2 (C1 i) (C1 i)
如果要隐藏S b
类型的单例参数,请查看this recent question。您可以使用类型类来实现。 E.g。
class CB b where getSB :: S b
instance CB B1 where getSB = SB1
instance CB B2 where getSB = SB2
intermediate_func :: SB b → Int → D b
intermediate_func SB1 i = D2 (C1 i) (C1 i)
intermediate_func SB2 i = D2 (C1 i) (C1 i)
intermediate_func_short :: CB b => Int → D b
intermediate_func_short = intermediate_func getSB
答案 1 :(得分:1)
使用类型类的解决方案:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
module Temp where
data A1
data A2
data B1
data B2
data C a b where
C1 :: Int -> C a b
C2 :: Char -> C A1 b
C3 :: Bool -> C A1 B1
class Intermediate b where
type ResT b
intermediate_func :: Int -> D b
data D b where
D1 :: ResT B1 -> C A1 B1 -> D B1
D2 :: ResT b -> C A1 b -> D b
instance Intermediate B1 where
type ResT B1 = C A1 B1
intermediate_func i = D2 (C1 i) (C1 i)
instance Intermediate B2 where
type ResT B2 = C A2 B2
intermediate_func i = D2 (C1 i) (C1 i)