Я хотел бы создать тип T
в Haskell, который позволяет
[Leaf 1, Rooted (Leaf 2), Branch (Leaf 3) (Branch (Leaf 4) (Leaf 5))]
но нет
[Leaf 1, Rooted (Leaf 2), Branch (Rooted (Leaf 3)) (Branch (Leaf 4) (Leaf 5))]
т.е. все конструкторы T
, кроме Rooted
, могут появляться в первом или втором аргументах Branch
(полный код имеет еще несколько конструкторов).
Я пробовал такие вещи, как
{-# LANGUAGE GADTs #-}
data T (x::Bool) where
Leaf :: Int -> T True
Rooted :: T True -> T False
Branch :: T True -> T True -> T True
что гарантирует, что мы не можем сделать Branch (Rooted …) …
, но также означает, что мы не можем сделать [Rooted …, One …]
, так как это будет список различных типов ([T True, T False]
).
Я изучил DataKinds, надеясь, что смогу сделать
{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
data T where
Leaf :: Int -> T
Rooted :: T -> T
Branch :: UnRooted a => a -> a -> T
class UnRooted a
instance UnRooted Leaf
instance UnRooted Branch
но тогда ghc (7.10.3) дает Data constructor ‘Leaf’ comes from an un-promotable type ‘T’
.
Есть ли способ сделать это в Haskell?
Rooted
? - person MathematicalOrchid   schedule 27.11.2017Branch
на самом деле представляет собой набор операторов для объединения двух выражений.Rooted
- это (набор) оберток, чтобы сказать, что такие вещи, как этот шаблон, не обязательно должны появляться рядом с предыдущим/следующим. Но кажется сложным определить такой тип простым и понятным способом, поэтому я думаю, что мне следует найти другой подход. - person unhammer   schedule 27.11.2017