是否可以在Haskell中为部分应用类型创建数据构造函数?
ghci session:
Prelude> data Vector a b = Vector {x::a, y::b}
Prelude> :t Vector
Vector :: a -> b -> Vector a b
Prelude> type T1 = Vector Int
Prelude> :t T1
<interactive>:1:1: Not in scope: data constructor `T1'
Prelude> let x = Vector
Prelude> let y = T1
<interactive>:46:9: Not in scope: data constructor `T1'
我想为T1类型创建数据构造函数 - 它甚至可能吗?或者我是否必须使用newtypes,因为无法手动定义此类函数?
答案 0 :(得分:6)
我对你的目标有点困惑,但让我们一点一点地经历这一点,也许我会找到正确的观点:
:t
告诉您变量的类型;应用于类型时没有任何意义,因为它只会返回您传递的内容。请注意,此处的错误告诉您:t
期望某种数据值作为参数:
Prelude> :t Maybe
<interactive>:1:1: Not in scope: data constructor `Maybe'
Prelude> :t (Maybe Integer)
<interactive>:1:2: Not in scope: data constructor `Maybe'
<interactive>:1:8: Not in scope: data constructor `Integer'
您可以创建部分类型:
Prelude> type T = Maybe
Prelude> Just 5 :: T Integer
Just 5
type T a = Maybe a -- alternately, with explicit type parameters
Prelude> Just 'a' :: T Char
Just 'a'
您无法为部分类型创建数据构造函数,因为它们不代表数据。 Maybe
或Vector
可以在没有对类型进行参数化的情况下获得什么值?您可能倾向于认为Maybe
的值为Nothing
,但Nothing
的类型为:{/ p>
Prelude> :t Nothing
Nothing :: Maybe a
关键是Nothing
可以任何 Maybe a
,但仍然需要a
才能知道它是Nothing
。 (有点像我告诉你“给我拿一杯”而不是“给我一杯任何东西” - 在我至少完成我的想法之前你不能有效地遵守。)
您当然可以创建部分应用的功能,这些功能会在应用后返回完整类型 :
Prelude> let f = Just :: a -> T a
Prelude> f 5
Just 5
Prelude> :t f 'a'
f 'a' :: T Char
答案 1 :(得分:4)
GADT可以做到这一点。 GHCi会议:
λ :set -XGADTs
λ :{
| data Vector a b where
| Vector :: a -> b -> Vector a b
| T1 :: Int -> b -> T1 b
| type T1 = Vector Int
| :}
λ :t T1
T1 :: Int -> b -> T1 b
答案 2 :(得分:1)
T1
已有一个构造函数,名为Vector
:
*Main> :t Vector :: Int -> b -> T1 b
Vector :: Int -> b -> T1 b :: Int -> b -> T1 b
答案 3 :(得分:1)
Prelude> type T1 = Vector Int
这会为Vector Int
创建类型构造函数。请注意,此处Vector
用作类型构造函数,因为您提供了类型参数。您可以使用T1
查询:k
类型的种类:
Prelude> :k T1
T1 :: * -> *
这告诉您T1
是一个类型构造函数,它采用具体类型(*
)并返回一个具体类型。
要创建数据构造函数,您需要为Vector
数据构造函数的第一个参数提供数据值:
Prelude> let t1 = Vector 5
Prelude> :t t1
t1 :: b -> Vector Integer b
(请注意,Vector
既是类型* 构造函数,也是数据构造函数,因为您在左侧和右侧使用了相同的名称data
声明。)