【问题标题】:How to draw from function with arguments in Haskell?如何从 Haskell 中带参数的函数中绘制?
【发布时间】:2014-11-01 10:04:52
【问题描述】:

我知道在do 块内我可以从一元的东西中提取,“提取”它的内容。例如,如果我有一个带有签名的函数:

myFunction :: MyReader (Set Int)

我可以在 do 块内执行此操作:

mySet <- myFunction

这会给我想要的Set Int。但是,如果我改变我的函数,让它接受一个参数:

myFunction :: Int -> MyReader (Set Int)

我不能再做我想做的事了:

myFunction' <- myFunction

编译失败,出现错误Couldn't match expected typeProbable cause: ‘myFunction'’ is applied to too few arguments。尝试这样的事情甚至在语法上都不正确:

myFunction' x <- myFunction x

我确实希望 myFunction' 的类型为 Int -&gt; Set Int。我无法弄清楚或找到任何地方如何做我想做的事。有人可以帮忙吗?

【问题讨论】:

  • 您认为myFunction' &lt;- myFunction 会做什么?基本上这仅在 MyReader monad 上下文中才有意义,但 myFunction' 不是一个函数。也许您的意思是mySet &lt;- myFunction 和类似的mySet &lt;- myFunctionWithAParameter 1
  • 不可能存在函数(Monad m) =&gt; (a -&gt; m b) -&gt; m (a -&gt; b)。这实质上意味着将一元函数转换为纯函数。
  • @NiklasB.- 你有没有参考证明不存在这样的功能?顺便说一句,我几乎可以肯定你说的是真的,但只是基于我脑海中一些挥之不去的东西,我希望看到更正式的东西。事实证明,谷歌搜索有点困难......
  • 如果您的Monad m 也是Distributive m(例如您的阅读器),那么您可以使用distribute :: (a -&gt; m b) -&gt; m (a -&gt; b)
  • @jamshidh 作为证明,假设它在任何单子中都是可能的,因此即使在延续单子中也是如此。然后,推导出一个(a -&gt; (b -&gt; r) -&gt; r) -&gt; ((a -&gt; b) -&gt; r) -&gt; r 类型的术语。选择r=a并释放第一个输入。然后推断((a -&gt; b) -&gt; a) -&gt; a。应用 Curry-Howard 并推导出皮尔斯定律。矛盾。与stackoverflow.com/questions/24141972/…中相同的技巧

标签: function haskell higher-order-functions do-notation


【解决方案1】:

这可能是您正在寻找的:(未经测试)

data MyEnv = MyEnv { myFn :: Int -> Set Int }
type MyReader a = Reader MyEnv a

myFunction :: Int -> MyReader (Set Int)

something = do
     ...
     myFunction' <- reader (\env x -> runReader (myFunction x) env)
     -- here myFunction' :: Int -> Set Int

不过,它有点难看,因为它打破了抽象并重新构建了它。也许有一种更简洁的方法,但由于不可能在任意 monad 中做同样的事情,我们确实需要以某种方式打破抽象。

您至少可以将血淋淋的细节保存在辅助函数中:

flipReader :: (a -> Reader b c) -> Reader b (a -> c)
flipReader r = reader (\y x -> runReader (r x) y)

然后:

something = do
    ...
    myFunction' <- flipReader myFunction

【讨论】:

  • flipReader 是来自Data.Distributivedistribute 的特例。
  • 嗯,你说得对,我认为它很丑。但它确实回答了我的问题!谢谢!
【解决方案2】:

这将起作用:

result <- myFunction x

基本上,myFunction 的类型为 a -&gt; MyReader b,所以myFunction x(其中x :: a)的类型为MyReader b。如您所知,您可以使用&lt;-MyReader b 获取值,因此上面的表达式有效。

Haskell “do” 表示法有点(非常松散地说)像一种小型简单的脚本语言,您可以在其中将“命令”链接在一起(再次,这是非常松散的说法),并将结果“存储”在“变量”中”。

  var1 <- command1
  var2 <- command2 var1

可以读作

  run command1, store the result in var1
  then
  run command2 using var1 as a parameter, store the result in var2

警告....

这个类比会在很多 monad 中失效,并且是完全错误的,但在早期,这几乎是初学者在一段时间内看到的唯一模式。

【讨论】:

  • 这对我来说失败了,因为x 不在范围内。这就是为什么我尝试将它添加到双方。
  • 我认为如果我了解您要解决的更大问题,这将更容易理解。你能就你试图解决的更广泛的问题在上面给出一句话吗?
  • 好吧,你已经编辑了你的答案,但它仍然没有给我我想要的东西。为了清楚起见,我希望左侧是 Int -&gt; Set Int 类型的函数。
  • 在这种情况下,没有。我不想解决我的问题。如果答案是 Haskell 不允许我使用带有 &lt;- 运算符的高阶函数,那就是我的答案。如果有一种方法可以轻松地将Int -&gt; MyReader (Set Int) 转换为MyReader (Int -&gt; Set Int),那将是一个更好的答案。
  • 我不确定类型系统是否允许这样做。 (a -&gt; m b) -&gt; m (a -&gt; b) 的快速 Hoogle search 什么也没找到。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多