从此 https://en.wikibooks.org/wiki/Haskell/Arrow_tutorial#Hangman:_Main_program
IO如何完成?格外
main :: IO ()
main = do
rng <- getStdGen
interact $ unlines -- Concatenate lines out output
. ("Welcome to Arrow Hangman":) -- Prepend a greeting to the output
. concat . map snd . takeWhile fst -- Take the [String]s as long as the first element of the tuples is True
. runCircuit (hangman rng) -- Process the input lazily
. ("":) -- Act as if the user pressed ENTER once at the start
. lines -- Split input into lines
Interact似乎是(string - &gt; string) - &gt; IO()。印象是它打印的是每行所读取的功能。令我困惑的是,如何打印初始线。存储在两者之间的状态在哪里?。
早先以一种已经生成所有输入的方式使用了runCircuit。我对这个版本如何逐行运行感到困惑,但似乎没有存储任何状态? Circuit String (Bool, [String])
如何以runCircuit :: Circuit a b -> [a] -> [b]
逐行方式运行?以某种方式似乎记得以前的结果在哪里?。
答案 0 :(得分:3)
Interact不会每行运行该函数。 interact
和runCircuit
是懒惰的。因为您在行中拆分输入并连接输出,所以当您提供越来越多的输入时,您将看到runCircuit
的进度。
函数runCircuit
定义如下:
runCircuit :: Circuit a b -> [a] -> [b]
runCircuit _ [] = []
runCircuit cir (x:xs) =
let (cir',x') = unCircuit cir x
in x' : runCircuit cir' xs
在那里,您可以看到在输入列表中为输入列表中的每个元素(每行)生成一个元素。这已经表明您将能够懒惰地处理列表。 (为了进行比较:如果需要xs
的长度来生成第一个输出x'
,那么runCircuit
将不变得懒惰。)
让我们将其与Circuit
:
data Circuit a b = Circuit { unCircuit :: a -> (Circuit a b, b) }
您运行电路的方式是,您提供x
类型的第一个输入a
,不仅可以获得x'
类型的第一个输出b
,还可以获得延续 Circuit
(cir'
中的runCircuit
)。此延续是新的Circuit a b
,由runCircuit
在下一次迭代中使用。这就是状态的保留方式:新的Circuit
将与原始的mySum :: Circuit Int Int
mySum = mySum' 0
mySum' :: Int -> Circuit Int Int
mySum' acc = Circuit $ \input ->
let acc' = acc + input
in (mySum' acc', acc')
类似,但它可能受到先前输入的影响。
例如,您可以定义一个对Ints求和并产生总和的电路。这篇文章中有一个例子,但是要使事情变得非常简单:
Circuit
在每次迭代中,返回的继续mySum' acc'
acc'
使用新的累加器Circuit
,其中包含到该点的总和。所以这个accum :: acc -> (a -> acc -> (b, acc)) -> Circuit a b
accum acc f = Circuit $ \input ->
let (output, acc') = input `f` acc
in (accum acc' f, output)
保持状态,因为它记住或结转到那时所有数字的总和。
回到那篇文章,稍微更通用的功能:
Circuit
在元组的第一个与自身不同的参数中返回 continuation accum acc f
。它被称为accum acc' f
,但延续为acc'
,其中input
取决于acc
和<?php
$a = [
85,
85167920,
'ELECTRICAL/ELECTRONIC',
'DEVICES',
'FOR',
'REPELLING',
'INSECTS',
'(E.G.MOSQUITOES
ETC)'
];
$b = [
85,
851680,
'ELECTRIC',
'HEATING',
'RESISTORS'
];
$aa = array_slice($a, 0,2);
$aa[] = implode(' ',array_slice($a, 2));
$bb = array_slice($b, 0,2);
$bb[] = implode(' ',array_slice($b, 2));
print_r($aa);
echo '<br>';
print_r($bb);
?>
,因此它会在此累加器中保留内存。 / p>
使用延续是非常非常常见的。我认为大多数管道/流处理框架和许多FRP实现都是这样做的,包括Yampa,Varying,Dunai和netwire。