Rou*_*len 3 haskell types gtk2hs
我正在努力让以下代码超过GHC:
getFirstChild :: (WidgetClass w1, WidgetClass w2) => w1 -> IO (Maybe w2)
getFirstChild parent = do
-- check if parent is a container
if parent `isA` gTypeContainer
-- if parent is a container get the first child
then do children <- containerGetChildren $! castToContainer parent
return $! Just $! children !! 0
else return Nothing
Run Code Online (Sandbox Code Playgroud)
即使乍一看它看起来像是一个Gtk2hs问题,但它确实是关于Haskell类型的系统.
当我尝试使用GHC编译此代码时,我收到以下错误消息:
Could not deduce (w2 ~ Widget)
from the context (WidgetClass w1, WidgetClass w2)
bound by the type signature for
getFirstChild :: (WidgetClass w1, WidgetClass w2) =>
w1 -> IO (Maybe w2)
at HsFu\Gtk\Widget.hs:(6,4)-(12,28)
`w2' is a rigid type variable bound by
the type signature for
getFirstChild :: (WidgetClass w1, WidgetClass w2) =>
w1 -> IO (Maybe w2)
at HsFu\Gtk\Widget.hs:6:4
Expected type: [w2]
Actual type: [Widget]
In the first argument of `(!!)', namely `children'
In the second argument of `($!)', namely `children !! 0'
Run Code Online (Sandbox Code Playgroud)
类型containerGetChildren是:
containerGetChildren :: ContainerClass self => self -> IO [Widget]
Run Code Online (Sandbox Code Playgroud)
该Widget类型本身的一个实例WidgetClass,所以我不明白为什么我不能拥有的返回类型getFirstChild指定函数w2就是实例WidgetClass.
有没有办法在Haskell中表达这一点而不使用类似的东西unsafeCoerce ?
TIA
不,没有办法.你的脱臼
getFirstChild :: (WidgetClass w1, WidgetClass w2) => w1 -> IO (Maybe w2)
Run Code Online (Sandbox Code Playgroud)
说你的函数可以返回任何 w2,只要它在WidgetClass中,但这是一个谎言,因为它只返回Widgets.Haskell不会让你误导这样的程序员.
假设我正在导入你的模块并写了
data MyWodget = ....
instance WidgetClass MyWodget where ....
Run Code Online (Sandbox Code Playgroud)
那么,Maybe MyWodget只要我将一些MyWodge放在另一个MyWodget中,你就可以从你的类型签名中期望你的函数可以返回一个,但是因为你在定义中使用的函数只能用于Widgets,Haskell不能在MyWodget上使用它,我的代码既可以进行类型检查,也可以进行类型检查.
你不会成为能够与unsafeCoerce解决这个问题,因为MyWodget根本是不以任何方式Widget的; haskell类型类允许您使用具有相同功能界面的真正不同的数据类型,因此您不能仅仅强制执行.
你可以定义自己的类
class FromWidget w where -- not a good name, I admit
fromWidget :: Widget -> w
Run Code Online (Sandbox Code Playgroud)
然后你可以使用fromWidget重写你的函数更通用:
getFirstChild :: (WidgetClass w1, FromWidget w2) => w1 -> IO (Maybe w2)
Run Code Online (Sandbox Code Playgroud)
只要我做,我就可以在MyWodget上使用它
instance FromWidget MyWodget where ....
Run Code Online (Sandbox Code Playgroud)
但我深深怀疑是否有办法以这种方式在WidgetClass中制作所有内容.也许你可以制作你感兴趣的每个WidgetClass,但也许你应该检查一下你是否真的只对Widgets感兴趣.
| 归档时间: |
|
| 查看次数: |
208 次 |
| 最近记录: |