我正在尝试为强类型文件路径制作通用免费类别(Path)和文件系统实例。我希望新的TypeInType
扩展可以实现这种更通用的路径类型,其中2013年my earlier efforts似乎需要将文件系统部分绑定到类别部分,但我遇到了问题我似乎不允许将数据系列实例推广到实物级别,即使它已被GHCI中的:kind
接受。
我可能会遗漏一些明显的东西;我现在已经离Haskell大部分时间并编程一段时间了,即便如此,我也不是高级类型编程专家。
我在GHC 8中试图实现的目标是什么?
{-# LANGUAGE TypeInType, TypeFamilies, GADTs #-}
import Data.Kind
data family Vertex g
data family Edge g (a :: Vertex g) (b :: Vertex g)
data Path g (a :: Vertex g) (b :: Vertex g) where
Nil :: Path g a a
Cons :: Edge g a b -> Path g b c -> Path g a c
data FileSystem
data instance Vertex FileSystem = Root | Home | Working | Directory | File
data instance Edge FileSystem where
RootDirectory :: Edge FileSystem Root Directory
HomeDirectory :: Edge FileSystem Home Directory
WorkingDirectory :: Edge FileSystem Working Directory
DirectoryName :: String -> Edge FileSystem Directory Directory
FileName :: String -> Edge FileSystem Directory File
FileExtension :: String -> Edge FileSystem File File
$ ghc Path.hs
[1 of 1] Compiling Main ( Path.hs, Path.o )
Path.hs:18:38: error:
• Data constructor ‘Root’ cannot be used here
(it comes from a data family instance)
• In the second argument of ‘Edge’, namely ‘Root’
In the type ‘Edge FileSystem Root Directory’
In the definition of data constructor ‘RootDirectory’
评论代码编译的Edge FileSystem
声明,我可以在GHCi中尝试一些事情。
*Main> :set -XTypeInType -XTypeFamilies -XGADTs
*Main> :k Edge FileSystem
Edge FileSystem :: Vertex FileSystem -> Vertex FileSystem -> *
*Main> :k Root
Root :: Vertex FileSystem
*Main> :k Edge FileSystem Root Directory
Edge FileSystem Root Directory :: *
答案 0 :(得分:4)
我认为您的解决方案过于复杂。那些Node
和Edge
数据系列是导致错误的原因 - data families aren't promoted,即使使用TypeInType
- 他们也没有通过以下更简单的设计添加任何内容:
infixr 5 :>
data Path (g :: k -> k -> *) (x :: k) (y :: k) where
Nil :: Path g x x
(:>) :: g x y -> Path g y z -> Path g x z
Path g
是g
s的类型对齐列表,因此g
s&#39}类型加入像多米诺骨牌。或者,将类型视为集合,Path g
是有向图的自由类别中的态射类型,其中k
中的节点和g :: k -> k -> *
中的边缘。或者,将g
视为逻辑关系,Path g
是g
的自反传递闭包。
在这种情况下,k
和g
分别是以下FileSystemItem
和FileSystemPart
类型:
data FileSystemItem = Root | Home | Working | Directory | File
data FileSystemPart (dir :: FileSystemItem) (base :: FileSystemItem) where
RootDirectory :: FileSystemPart Root Directory
HomeDirectory :: FileSystemPart Home Directory
WorkingDirectory :: FileSystemPart Working Directory
DirectoryName :: String -> FileSystemPart Directory Directory
FileName :: String -> FileSystemPart Directory File
FileExtension :: String -> FileSystemPart File File
type FileSystemPath = Path FileSystemPart
所以FileSystemPath
是FileSystemItem
s类别中的态射集:
ghci> :k FileSystemPath
FileSystemPath :: FileSystemItem -> FileSystemItem -> *
例如:
myDocument :: FileSystemPath Home File
myDocument = HomeDirectory :> DirectoryName "documents" :> FileName "foo" :> FileExtension "hs" :> Nil
请注意,您不需要TypeInType
或TypeFamilies
重型机器 - 您只需要PolyKinds
来定义类型多态Path
,并且文件系统本身DataKinds
加GADTs
。