使用TypeInType进行数据族实例的类型提升

时间:2016-09-09 11:51:30

标签: haskell

我正在尝试为强类型文件路径制作通用免费类别(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’

GHCI

评论代码编译的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 :: *

1 个答案:

答案 0 :(得分:4)

我认为您的解决方案过于复杂。那些NodeEdge数据系列是导致错误的原因 - 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 gg s的类型对齐列表,因此g s&#39}类型加入像多米诺骨牌。或者,将类型视为集合,Path g是有向图的自由类别中的态射类型,其中k中的节点和g :: k -> k -> *中的边缘。或者,将g视为逻辑关系,Path gg的自反传递闭包。

在这种情况下,kg分别是以下FileSystemItemFileSystemPart类型:

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

所以FileSystemPathFileSystemItem s类别中的态射集:

ghci> :k FileSystemPath
FileSystemPath :: FileSystemItem -> FileSystemItem -> *

例如:

myDocument :: FileSystemPath Home File
myDocument = HomeDirectory :> DirectoryName "documents" :> FileName "foo" :> FileExtension "hs" :> Nil

请注意,您不需要TypeInTypeTypeFamilies重型机器 - 您只需要PolyKinds来定义类型多态Path,并且文件系统本身DataKindsGADTs