Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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 GHC为同一表达式选择不同的实例?_Haskell_Ghc_Typeclass - Fatal编程技术网

Haskell GHC为同一表达式选择不同的实例?

Haskell GHC为同一表达式选择不同的实例?,haskell,ghc,typeclass,Haskell,Ghc,Typeclass,我想实现一个带有arr-成员函数的箭头,该函数显示不同类型的函数参数的不同行为,例如arr(\x->(x,x))的行为应该与arr id不同 代码如下: {-# LANGUAGE Arrows, OverlappingInstances, IncoherentInstances, FlexibleInstances#-} import Control.Arrow import Control.Category import Prelude hiding (id, (.)) class ToP

我想实现一个带有
arr
-成员函数的箭头,该函数显示不同类型的函数参数的不同行为,例如
arr(\x->(x,x))
的行为应该与
arr id
不同

代码如下:

{-# LANGUAGE Arrows, OverlappingInstances, IncoherentInstances, FlexibleInstances#-}
import Control.Arrow
import Control.Category 
import Prelude hiding (id, (.))

class ToPredefinedStr a where
  toStr :: a -> String


instance ToPredefinedStr ((->) b (b,b)) where
  toStr _ = "b -> (b,b)"

instance ToPredefinedStr (a -> (b,c)) where
  toStr _ = "a -> (b,c)" 

instance ToPredefinedStr ((a,b) -> c) where
  toStr _ = "(a,b) -> c"

instance ToPredefinedStr (a -> b) where 
  toStr _ = "a -> b"

newtype MyArrow a b c = MA (a b (c, String))

instance (Category a, Arrow a) => Category (MyArrow a) where
    -- irrelevant for this example ...

instance (Arrow a) => Arrow (MyArrow a) where
    arr f        = MA (arr (\x -> (f x, toStr f)))

appMyArr (MA a) = a
但是:它显示了以下非常奇怪的行为:

> toStr (\x -> (x,x)) -- that works as expected!
"b -> (b,b)" 
> appMyArr (arr (\x -> (x,x))) () -- but this does'nt!!
(((),()),"a -> b")

有人能解释一下如何让ghci为第二个示例中的表达式
\x->(x,x)
选择
b->(b,b)
-实例吗

如果使用
不连贯
任何事情都可能发生。不再有任何承诺,这些实例是以连贯的方式挑选的

简单的回答是,发生这种情况是因为编译器在第一种情况下比在第二种情况下可以访问更具体的类型信息

编译
arr
的定义时,编译器只将函数参数
f
的类型视为
b->c
,因此在考虑调用
toStr f
时,它必须仅基于此信息选择一个实例。毕竟,
arr
可以用任何函数调用。很明显,它只能选择
实例toprefinedstr(a->b)

现在,当我们像在
toStr(\b->(b,b))
中那样内联它时,编译器在调用站点上有更多可用信息,可以选择更具体的实例

不,如果您考虑到这一点,使用
INLINE
pragmas不会更改实例选择

对于您试图实现的目标,我能想到的最接近的方法是限制类型,以便在
arr
之外进行实例选择:

{-# LANGUAGE FlexibleContexts, ... #-}

class FancyArrow a where
    myArr :: (ToPredefinedStr (b -> c)) => (b -> c) -> a b c 
    ...

instance (Arrow a) => FancyArrow (MyArrow a) where
    myArr f        = MA (arr (\x -> (f x, toStr f)))
这会得到您想要的结果

*Main> appMyArr (myArr (\x -> (x,x))) ()
(((),()),"b -> (b,b)")
请注意,这有点脆弱,因为您必须通过传播
topreferencedstr
约束来控制实例选择的位置。例如,如果删除类型签名,此函数将以静默方式更改行为

foo :: (Arrow a, ToPredefinedStr (b -> c)) => (b -> c) -> a b (c, String)
foo f = appMyArr (myArr f)

我想,不连贯性会从上到下,挑选出符合……的第一个实例?@phynfo:第一个符合上下文推断类型的实例。我不清楚细节,GHC用户指南在这个问题上有些沉默寡言,但哈马尔的回答听起来似乎有道理。但事实上,这是不连贯的。上面写着名字。你期待什么?:]一个有趣的建议;我明天一定会试试的。。。为什么你认为它不能工作?主要是因为它不能与标准的
Arrow
类一起工作,但是如果你对此没问题,那么它肯定会工作。然而,它感觉有点脆。