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 FunctionalDependencies不统一于唯一标识的类型_Haskell_Functional Dependencies_Type Families - Fatal编程技术网

Haskell FunctionalDependencies不统一于唯一标识的类型

Haskell FunctionalDependencies不统一于唯一标识的类型,haskell,functional-dependencies,type-families,Haskell,Functional Dependencies,Type Families,以下是MonadState的定义,但问题适用于具有功能依赖性的任何此类类: class Monad m=>MonadState s m | m->s where ... 假设我有一个使用s作为类型参数的数据类型和一个使用它的类型类: data StateType s=StateType 类MonadState s m=>FunDeps s m a其中 workWithStateType::a->StateType s->m() 我可以很高兴地为这个类创建一个实例,它可以按照预期编译和工作:

以下是
MonadState
的定义,但问题适用于具有
功能依赖性的任何此类类:

class Monad m=>MonadState s m | m->s where
...
假设我有一个使用
s
作为类型参数的数据类型和一个使用它的类型类:

data StateType s=StateType
类MonadState s m=>FunDeps s m a其中
workWithStateType::a->StateType s->m()
我可以很高兴地为这个类创建一个实例,它可以按照预期编译和工作:

实例(MonadIO m,MonadState s m)=>FunDeps s s m(IORef(StateType s)),其中
workWithStateType ref a=liftIO$writeIORef ref a
但我觉得
FunDeps
类中的
s
是多余的,我可以这样定义一个类:

class-fundepsma在哪里
workWithStateTypeNoCompile::MonadState s m=>a->StateType s->m()
实例(MonadIO m,MonadState s m)=>fundeps问题m(IORef(StateType s)),其中
...
问题是当我尝试实施它时:

instance (MonadIO m, MonadState s m) => FunDepsProblem m (IORef (StateType s)) where
  workWithStateTypeNoCompile ref a = liftIO $ writeIORef ref a
我得到一个编译错误,它告诉我它不能统一实例头和函数中的状态标记
s


fun-deps.hs:18:62: error: …
    • Couldn't match type ‘s1’ with ‘s’
      ‘s1’ is a rigid type variable bound by
        the type signature for:
          workWithStateTypeNoCompile :: forall s1.
                                        MonadState s1 m =>
                                        IORef (StateType s) -> StateType s1 -> m ()
        at /path/to/fun-deps.hs:18:3-28
      ‘s’ is a rigid type variable bound by
        the instance declaration
        at /path/to/fun-deps.hs:17:10-78
      Expected type: StateType s
        Actual type: StateType s1
    • In the second argument of ‘writeIORef’, namely ‘a’
      In the second argument of ‘($)’, namely ‘writeIORef ref a’
      In the expression: liftIO $ writeIORef ref a
    • Relevant bindings include
        a :: StateType s1
          (bound at /path/to/fun-deps.hs:18:34)
        ref :: IORef (StateType s)
          (bound at /path/to/fun-deps.hs:18:30)
        workWithStateTypeNoCompile :: IORef (StateType s)
                                      -> StateType s1 -> m ()
          (bound at /path/to/fun-deps.hs:18:3)
   |
Compilation failed.
我理解,当它以这种形式定义时,所有
都有一个隐含的

  workWithStateTypeNoCompile :: forall s m a . MonadState s m => a -> StateType s -> m ()
所以从技术上讲,它应该适用于每一个
s
,在没有
功能依赖性的情况下,它是完全有意义的,但是
s
m
已知时是已知的,所以这是我没有得到的部分

换句话说,monad
m
在类头和函数中是统一的,因此它应该唯一地标识实例头和函数类型中的状态类型
s
。所以我的问题是为什么它没有统一?这是否有理论上的原因,或者根本没有在ghc中实施

事实上,如果我将
MonadState
重写为概念上相同的功能,但使用
TypeFamilies
而不是
FunctionalDependencies
则问题似乎消失了:

class Monad m=>monadstate族m其中
键入StateToken m::*
班级家庭m a在哪里
familyStateType::MonadStateFamily m=>a->StateType(StateToken m)->m()
实例(MonadIO m,MonadStateFamily m,s~StateToken m)=>Family m(IORef(StateType s)),其中
familyStateType ref a=liftIO$writeIORef ref a

显然,这是
功能相关性的已知限制。我在十多年前挖了一家Haskell咖啡馆,其中提到
功能依赖性
不适用于存在类型,并提供了一个非常简洁明了的示例:

类别F a r | a->r
实例F Bool Int
数据T a=全部b。fab=>mktb
添加::T Bool->T Bool->T Bool
加上(MkT x)(MkT y)=MkT(x+y)
上面的例子产生了一个编译器错误,它说它不能统一到唯一标识的类型上,本质上就是问题的标题

    • Couldn't match expected type ‘b’ with actual type ‘b1’
      ‘b1’ is a rigid type variable bound by
        a pattern with constructor: MkT :: forall a b. F a b => b -> T a,
        in an equation for ‘add’
这是问题中的编译错误,看起来与上面的问题非常相似

    • Couldn't match type ‘s1’ with ‘s’
      ‘s1’ is a rigid type variable bound by
        the type signature for:
          workWithStateTypeNoCompile :: forall s1.
                                        MonadState s1 m =>
                                        IORef (StateType s) -> StateType s1 -> m ()
我怀疑这里使用的是完全相同的概念,因为
workWithStateTypeNoCompile
上的
forall
,错误中的类型变量
s1
是存在变量

在任何情况下,并不是所有的东西都丢失了,对于我遇到的问题,有一个体面的解决办法。尤其需要从类实例头中删除
s
,这可以通过
newtype
实现:

class-fundepsma在哪里
WorkWithStateTypeComile::MonadState s m=>a s->StateType s->m()
newtype StateTypeRef s=StateTypeRef(IORef(StateType s))
实例MonadIO m=>FundepWorks m StateTypeRef,其中
workWithStateTypeCompile(StateTypeRef)a=liftIO$writeIORef ref a
请注意,
a
现在是一个arity为1的类型变量,并应用于
s


多亏了Ben Gamari编译了wiki页面,否则我将永远不会发现存在类型的例子。

思考:当您启用-XScopedTypeVariables并给
workWithStateTypeNoCompile
一个显式统一变量的签名时会发生什么?@bradrn值得一试,但运气不佳,同样的错误。我相信GHC只是没有把
函数依赖性
视为“函数”。也就是说,没有与之相关的新类型公理。即使你知道
classcab | a->b;实例C A B;实例C A C
,没有证据证明
B~C
。函数依赖关系实际上是“推理”:如果需要
实例ca\u b
\u b
未知,那么可以选择一个实例(不连贯地)将
\u b
设置为一个类型,这是由对实例编写的限制(即
b
C
无论如何必须相同)证明的,但这种平等性并没有作为系统本身的一项规则内在化。@HTNW但FunDeps确保这样的实例不能共存:
实例C a B;实例C A C
。这样的实例也是非法的:
实例C A\u b
并且任何扩展都不能让您不连贯地拾取它。所以我不太明白你的论点,那是Haskell类型系统的一个真实属性,但是在Haskell类型系统中,根本没有办法证明这一点。例如,
excl::或者a(a->Void)
也不可能在(全部)Haskell中写入,但是没有
反经典::(对于所有a.或者a(a->Void))->Void
。也就是说,有些事情不是真的,但也不是假的。在这种情况下,
B
C
必须是相同的才能通过实例,但在Haskell内部证明这一点是不正确的。