2

我知道在一个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 -> Set Int。我无法弄清楚或找到任何地方如何做我想做的事。有人可以帮忙吗?

4

2 回答 2

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
于 2014-11-01T13:42:25.220 回答
0

这将起作用:

result <- myFunction x

基本上,myFunction有类型a -> MyReader b,所以myFunction x(哪里x :: a)有类型MyReader b。如您所知,您可以MyReader b通过 using获取值<-,因此上面的表达式有效。

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

警告....

有很多单子,这个类比会被打破,并且是完全错误的,但在早期,这几乎是初学者在一段时间内看到的唯一模式。

于 2014-11-01T10:08:00.107 回答