我正在为idleCallback
提供一个函数。这种符号有效:
idleCallback $= Just (do
modifyIORef world play
postRedisplay Nothing)
为什么这个(看似相似的)符号不起作用?
idleCallback $= Just $ do
modifyIORef world play
postRedisplay Nothing
为了保存你的胡扯,类型是:
($=) :: HasSetter s => s a -> a -> IO ()
type IdleCallback = IO ()
data SettableStateVar a
idleCallback :: SettableStateVar (Maybe IdleCallback)
postRedisplay :: Maybe Window -> IO ()
modifyIORef :: IORef a -> (a -> a) -> IO ()
GHC说:
Couldn't match expected type `Maybe IdleCallback'
with actual type `a0 -> Maybe a0'
In the second argument of `($=)', namely `Just'
In the expression: idleCallback $= Just
In a stmt of a 'do' block:
idleCallback $= Just
$ do { modifyIORef world play;
postRedisplay Nothing }
这可以在不将do
块包裹在括号中的情况下编写吗?
答案 0 :(得分:9)
这是一个优先级错误....($=
)绑定比($
)更紧密。您可以在错误消息中看到:
Couldn't match expected type `Maybe IdleCallback'
with actual type `a0 -> Maybe a0'
In the second argument of `($=)', namely `Just'
它认为($=
)的第二个参数只是Just
(它是一个引用函数的有效Haskell类型)。如果你将括号括在整个Just
,包括do
- 块,它应该可以工作。
答案 1 :(得分:2)
$
不是保存括号的特殊符号,它是一个普通函数(带有中缀运算符)。因此,不能意味着“将所有内容括在右边”。它实际意味着“将我的第一个论点应用于我的第二个论点”。
因此,它通常用于保存括号,但不是在这里因为:
idleCallback $= Just $ do
modifyIORef world play
postRedisplay Nothing
将使用不$
和更多括号重写:
(idleCallback $= Just) (do
modifyIORef world play
postRedisplay Nothing)
而不是你想要的。原因是,一旦您将运算符优先级/关联性表示法转换为显式格式,它实际上就会被解析为:
($) (idleCallback $= Just) (do
modifyIORef world play
postRedisplay Nothing)
核心问题是$=
也不是特殊语法,而是普通函数(使用中缀表示法),而$
的优先级低于$=
;设计$
具有极低的优先级;这使得它通常适用于正常代码中的括号减少,但是当你将包含$
的正确表达式作为更大表达式的一部分移动到新上下文中时,通常会导致失败的原因。
进行这种转换的唯一完全通用的方法(当你推断Just $ do ...
有效时,你正在隐式执行这一操作,因此idleCallback $= Just $ do ...
也应该有效)是将完整表达式包装在在将它插入外部表达式之前将括号括起来(这将产生idleCallback $= (Just $ do ...)
,这确实可以正常工作)。实际上,所有表达式都是如此,特别是涉及运算符时。例如您会自动知道仅因为x + y
有效并不意味着当您将其放入z * ___
中的空白时它仍然可以按照您想要的方式工作;你必须盲目地括起来获得z * (x + y)
,或者根据具体情况推断具体代码,看你是否需要括号(或其他转换)。
答案 2 :(得分:1)
你的里程可能会有所不同,但是有一件事应该有效,除非$=
具有最高优先级
idleCallback $= Just `id` do
...
这是有效的,因为id
作为运算符没有定义优先级,因此默认情况下获得最高值。