Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将类型族实例转换为Int_Haskell_Type Families - Fatal编程技术网

Haskell 将类型族实例转换为Int

Haskell 将类型族实例转换为Int,haskell,type-families,Haskell,Type Families,我有以下代码: type family Id obj :: * type instance Id Box = Int 我想这样做,这样我就可以从Id类型族中得到一个Int。我认识到需要进行转换 我想也许创建一个类会有用: class IdToInt a where idToInt :: Id a -> Int instance IdToInt Box where idToInt s = s 这实际上是编译的。但当我尝试使用它时: testFunc :: Id a ->

我有以下代码:

type family Id obj :: *
type instance Id Box = Int
我想这样做,这样我就可以从Id类型族中得到一个Int。我认识到需要进行转换

我想也许创建一个类会有用:

class IdToInt a where
  idToInt :: Id a -> Int

instance IdToInt Box where
  idToInt s = s
这实际上是编译的。但当我尝试使用它时:

testFunc :: Id a -> Int
testFunc x = idToInt x
我得到一个错误:

src/Snowfall/Spatial.hs:29:22:
Couldn't match type `Id a0' with `Id a'
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x
那么,如何为类型族Id创建转换以获得Int

根据ehird的回答,我尝试了以下方法,但也不起作用:

class IdStuff a where
  type Id a :: *
  idToInt :: Id a -> Int

instance IdStuff Box where
  type Id Box = Int
  idToInt s = s

testFunc :: (IdStuff a) => Id a -> Int
testFunc x = idToInt x
它给出了错误:

src/Snowfall/Spatial.hs:45:22:
Could not deduce (Id a0 ~ Id a)
from the context (IdStuff a)
  bound by the type signature for
             testFunc :: IdStuff a => Id a -> Int
  at src/Snowfall/Spatial.hs:45:1-22
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x

你不能。您需要
testFunc::(IdToInt a)=>ida->Int
。类型族是开放的,因此任何人都可以声明

type instance Id Blah = ()
在任何时间,并没有提供转换功能。最好将类型族放入类中:

class HasId a where
  type Id a
  idToInt :: Id a -> Int

instance IdToInt Box where
  type Id Box = Int
  idToInt s = s

但是,您仍然需要上下文。

您不能使用类型为
IdToInt a=>Id a->Int
的函数,因为无法确定
a
是什么类型。下面的示例演示了这一点

type family Id a :: *
type instance Id () = Int
type instance Id Char = Int

class IdToInt a where idToInt :: Id a -> Int

instance IdToInt () where idToInt x = x + 1
instance IdToInt Char where idToInt x = x - 1

main = print $ idToInt 1
由于
Id()=Id Char=Int
,上述上下文中
idToInt
的类型是
Int->Int
,它等于
Id()->Int
Id Char->Int
。请记住,重载方法是根据类型选择的。两个类实例都定义了类型为
Int->Int
idToInt
函数,因此类型检查器无法决定使用哪一个

您应该使用数据族而不是类型族,并声明新类型实例

data family Id a :: *
newtype instance Id () = IdUnit Int
newtype instance Id Char = IdChar Int

对于newtype实例,
Id()
Id Char
都是int,但它们有不同的类型。
Id的类型通知类型检查器要使用哪个重载函数。

正如其他人所指出的,问题是编译器无法确定要使用哪个
a
。数据族是一种解决方案,但有时更容易使用的另一种方法是使用类型见证

把你的班级改成

class IdToInt a where
  idToInt :: a -> Id a -> Int

instance IdToInt Box where
  idToInt _ s = s

-- if you use this a lot, it's sometimes useful to create type witnesses to use
box = undefined :: Box

-- you can use it like
idToInt box someId

-- or
idToInt someBox (getId someBox)

您需要回答的问题是,对于任何给定的
Id
,是否只有一种类型
a
应该与之一起出现?也就是说,
a
s和
Id a
s之间是否存在一对一的对应关系?如果是这样,数据族是正确的方法。如果没有,您可能更喜欢证人。

谢谢。我还是不明白。我根据你在问题中的回答发布了我的结果,以便正确格式化。@taotree:哦,那是因为你使用的是类型同义词族,而不是数据类型族。这个特定的问题实际上可能是一个bug,但一般来说,类型同义词族是毫无用处的;由于两个实例完全有可能具有相同的关联类型,因此GHC几乎放弃了推导任何内容,最终导致混乱。使用数据类型族将解决所有这些问题。