所以,我要解决这个Haskell问题:
定义一个mapIO
函数,它接收一个函数f
和一个输入和输出动作a
,并产生一个输入和输出动作,当执行时,它执行给定的动作{{ 1}}并将a
的应用程序返回到f
的返回值。
这是我的代码:
a
它编译但不起作用。当我尝试执行与以下执行示例相同的操作时,它不起作用。拜托,有人可以帮帮我吗?
mapIO f a = do b <- a
return f(b);
答案 0 :(得分:8)
在许多其他语言中,g(x)
是将函数g
应用于参数x
的语法。在Haskell中,并置就足够了,因此g x
将g
应用于x
。巧合的是,这意味着g(x)
也是有效的语法,将g
应用于值(x)
,与x
相同,所以初学者似乎g(x)
是函数应用程序的正确语法。但它不是,而且这种困惑在这里咬了你。
当您编写return f(b)
时,您可能会认为这意味着使用特殊语法return
并且要返回的东西应该是函数应用程序f(b)
。但是,return
本身就是Haskell中的一个函数。所以它实际上意味着将return
应用于函数f
,然后将结果应用于术语(b)
。 (在这种意义上,功能应用是&#34;左关联&#34;)
幸运的是,与其他关联性问题一样,函数应用程序关联性问题的修复是使用括号。所以:
return (f(b))
或者,没有巧合正确的额外括号:
return (f b)
这只留下了为何&#34;工作的问题&#34; (在编译和类型检查的意义上)return f(b)
形式。这是一个高级主题;但事实证明,函数也与Monad
形成return = const
,因此return f(b)
实际上意味着const f(b)
,它会丢弃(b)
项。 (除此之外:除了允许使用Monad
的函数实例外,我们还必须在这里使用Monad
的函数实例。由于我们将return f
应用于(b)
,因此return f
的类型必须是函数。)因此,您的定义与以下内容相同:
mapIO' f a = do b <- a
f
即:首先执行a
,抛弃其结果,然后执行f
,就像它是另一个输入/输出操作一样。如果你检查mapIO
的推断类型,你会发现它符合这种直觉:
mapIO :: Monad m => m b -> m t -> m b
糟糕!