让重命名函数中断代码 [英] Let-renaming function breaks code

查看:76
本文介绍了让重命名函数中断代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  { - #LANGUAGE RankNTypes# -   - } 

模块Foo其中

导入Data.Vector.Generic.Mutable为M
导入Control.Monad.Primitive

- 具有维度
数据的就地向量函数DimFun vmr =
DimFun Int(v(PrimState m)r - > m())

eval ::(PrimMonad m ,MVector vr)=> DimFun v m r - > v(PrimState m)r - > m()
eval = error

iterateFunc ::(PrimMonad m,MVector v r)
=> (M vctor v'r)=> DimFun v'm r) - > DimFun v m r
iterateFunc = error

f ::(PrimMonad m,MVector v r)
=> DimFun v m r
f =错误

iteratedF ::(MVector v r,PrimMonad m)
=> v(PrimState m)r - > m()
iteratedF y =
let f'= f
in eval(iterateFunc f')y

此代码无法编译:

  Testing / Foo.hs:87:14: 
由于上下文(MVector vr,PrimMonad m)使用'f'
引起的
无法推断(MVector v0 r)

类型签名绑定iteratedF: :(MVector vr,PrimMonad m)=>
v(PrimState m)r - > m()
在Testing / Foo.hs:(84,14) - (85,39)
类型变量'v0'不明确
相关绑定包括
f'
y :: v(PrimState m)r(绑定在Testing / Foo.hs:86:11)
iteratedF :: DimFun v0 mr(绑定在Testing / Foo.hs:87:9) v(PrimState m)r - >
在表达式中:f
在'f''等式中:f'= f
(在Testing / Foo.hs:86:1处绑定)在表达式中:let f'= f in eval(iterateFunc f')y

测试/ Foo.hs:88:26:
无法将类型'v0'与'v ''
,因为类型变量'v''将会跳过它的范围
这个(rigid,skolem)类型变量受上下文所期望的
a类型的约束:MVector v'r => DimFun v'mr
在Testing / Foo.hs:88:14-27
期望类型:DimFun v'mr
实际类型:DimFun v0 mr
相关绑定包括
$'在'iterateFunc'的第一个参数中,即'f''
在'第一个参数' eval',即'(iterateFunc f')'
失败,模块加载:无。

但是,如果我更改 iteratedF to

  iteratedF y = eval(iterateFunc f)y 

代码编译为GHC 7.8.2。这个问题不是关于奇怪的签名或数据类型,只是这个:为什么将 f 重命名为 f'

解决方案

这个问题当然不是重命名,而是绑定到一个新的变量。由于 iterateFunc 是Rank-2,它需要一个多态参数函数。当然, f v 中是多态的,所以可以使用它。但是当你写 f'= f 时,目前还不清楚 f'应该是什么类型: f 或者一些单形类型,可能依赖于编译器没有推导出的 iteratedF 中另一个类型变量的关系还有。



编译器默认为单形选项;因为chi说这是单态限制的缺点,所以如果你把它关掉,你的代码实际上会被编译。

但是,即使没有单态的限制,同样的问题也会出现 RankNTypes 代码,它不能完全避免。唯一可靠的解决方案是本地签名,通常需要 ScopedTypeVariables


While iterating my code towards a correct version, I came across the following curiosity:

{-# LANGUAGE RankNTypes #-}

module Foo where

import Data.Vector.Generic.Mutable as M
import Control.Monad.Primitive

-- an in-place vector function with dimension
data DimFun v m r = 
  DimFun Int (v (PrimState m) r -> m ())

eval :: (PrimMonad m, MVector v r) => DimFun v m r -> v (PrimState m) r -> m ()
eval = error ""

iterateFunc :: (PrimMonad m, MVector v r)
            => (forall v' . (MVector v' r) => DimFun v' m r) -> DimFun v m r
iterateFunc = error ""

f :: (PrimMonad m, MVector v r)
      => DimFun v m r
f = error ""

iteratedF :: (MVector v r, PrimMonad m) 
           => v (PrimState m) r -> m ()
iteratedF y = 
    let f' = f
    in eval (iterateFunc f') y

This code does not compile:

Testing/Foo.hs:87:14:
    Could not deduce (MVector v0 r) arising from a use of ‘f’
    from the context (MVector v r, PrimMonad m)
      bound by the type signature for
                 iteratedF :: (MVector v r, PrimMonad m) =>
                              v (PrimState m) r -> m ()
      at Testing/Foo.hs:(84,14)-(85,39)
    The type variable ‘v0’ is ambiguous
    Relevant bindings include
      f' :: DimFun v0 m r (bound at Testing/Foo.hs:87:9)
      y :: v (PrimState m) r (bound at Testing/Foo.hs:86:11)
      iteratedF :: v (PrimState m) r -> m ()
        (bound at Testing/Foo.hs:86:1)
    In the expression: f
    In an equation for ‘f'’: f' = f
    In the expression: let f' = f in eval (iterateFunc f') y

Testing/Foo.hs:88:26:
    Couldn't match type ‘v0’ with ‘v'’
      because type variable ‘v'’ would escape its scope
    This (rigid, skolem) type variable is bound by
      a type expected by the context: MVector v' r => DimFun v' m r
      at Testing/Foo.hs:88:14-27
    Expected type: DimFun v' m r
      Actual type: DimFun v0 m r
    Relevant bindings include
      f' :: DimFun v0 m r (bound at Testing/Foo.hs:87:9)
    In the first argument of ‘iterateFunc’, namely ‘f'’
    In the first argument of ‘eval’, namely ‘(iterateFunc f')’
Failed, modules loaded: none.

However, if I change the definition of iteratedF to

iteratedF y = eval (iterateFunc f) y

the code compiles wtih GHC 7.8.2. This question is not about the strange-looking signatures or data types, it is simply this: why does renaming f to f' break the code? This seems like it has to be a bug to me.

解决方案

The problem is of course not the renaming, but the binding to a new variable. Since iterateFunc is Rank-2, it needs a polymorphic argument function. Of course, f is polymorphic in v, so it can be used. But when you write f' = f, it's not clear what type f' should be: the same polymorphic type as f, or some monomorphic type, possibly depending some relation to another type variable in iteratedF which the compiler hasn't deduced yet.

The compiler defaults to the monomorphic option; as chi says this is the monomorphism restriction's fault here so if you turn it off your code actually compiles.

Still, the same problem can turn up even without the monomorphism restriction in RankNTypes code, it can't be avoided completely. The only reliable fix is a local signature, usually necessitating ScopedTypeVariables.

这篇关于让重命名函数中断代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆