如何在Idris中使用相互定义的Streams?

时间:2018-06-10 16:17:07

标签: idris

我所遇到的问题可能比问题中所说的更为笼统。我正在尝试使用以下程序:

module Main
main: IO ()


process: Int -> Int
process req = req+1
server: Stream Int -> Stream Int
client: Int        -> Stream Int -> Stream Int
server (req :: reqs)           = process req :: server reqs
client initreq (resp :: resps) = initreq :: client resp resps
mutual
  reqsOut: Stream Int
  respsOut: Stream Int
  -- This fixes the segfault:
  -- reqsOut  = cycle [1, 2, 3, 4]
  reqsOut  = client 0 respsOut
  respsOut = server reqsOut

main = do
  printLn(take 5 reqsOut)

如果我将reqsOut的定义与注释版本交换,它将会运行,但会按原样生成分段错误。我的猜测是我错误地使用mutual,但我不确定如何。

1 个答案:

答案 0 :(得分:2)

请注意,在函数调用中,事先会对参数进行求值,特别是在拆分时。在client中,流使用client initreq (req :: reqs)进行分割,因此respsOut中的client 0 respsOut会在延迟尾部之前进行评估:

reqsOut =
client 0 respsOut =
client 0 (case respsOut of (req :: reqs) => ...) =
client 0 (case (server regsOut) of (req :: regs) => ...) =
...

您可以使用

延迟拆分
client initreq stream = initreq :: client (head stream) (tail stream)

但是你仍然可以通过server无限循环:

reqsOut =
client 0 respsOut =
client 0 (server regsOut) =
client 0 (case regsOut of (req :: reqs) => ...) =
...

您可以通过创建参数respsOut来延迟Lazy的计算:

client : Int -> Lazy (Stream Int) -> Stream Int
client initreq stream = initreq :: client (head stream) (tail stream)

现在client最终可以在不评估其参数的情况下构造Stream Int

client 0 respsOut =
0 :: Delay (client (head (Force respsOut)) (tail (Force respsOut))) : Stream int