Понимание этого кода требует двух навыков:
- различение между «определением», которое может быть бесконечным (например, набор натуральных чисел:
naturals = (1 : map '\n->n+1' naturals
) или список обработанных запросов) и «сокращением», которое представляет собой процесс сопоставления фактических данных с этими определениями
- видя структуру этого клиент-серверного приложения: это просто пара процессов, говорящих друг с другом: на самом деле «клиент-сервер» - это плохое имя: его следовало называть «wallace-gromit» или «foo-bar» ', или говорят философы или что-то еще, но это симметрично: обе стороны равны.
Как уже говорил Джон , сокращение работает ленивым способом (иначе называемый «вызов по необходимости»): take 2 naturals
не будет сначала оценивать полный набор натуральных чисел, а просто возьмет первый и добавьте это к take 1 (map '\n->n+1' naturals)
, которое уменьшится до [1, (1 + 1)] = [1,2].
Теперь структура клиент-серверного приложения такова (на мой взгляд):
server
- это способ создать список ответов из списка запросов с помощью функции process
client
- это способ создания запроса на основе ответа и добавления ответа этого запроса в список ответов.
Если вы присмотритесь, вы увидите, что оба являются «способом создания x: xs из y: ys». Таким образом, мы могли бы равномерно назвать их wallace
и gromit
.
Теперь было бы легко понять, если бы client
вызывался только со списком ответов:
someresponses = wallace 0 [1,8,9] -- would reduce to 0,1,8,9
tworesponses = take 2 someresponses -- [0,1]
Если ответы не известны буквально, но производятся gromit
, мы можем сказать
gromitsfirstgrunt = 0
otherresponses = wallace gromitsfirstgrunt (gromit otherresponses)
twootherresponses = take 2 otherresponses -- reduces to [0, take 1 (wallace (gromit ( (next 0):...) )]
-- reduces to [0, take 1 (wallace (gromit ( 0:... ) ) ) ]
-- reduces to [0, take 1 (wallace (1: gromit (...) ) ) ]
-- reduces to [0, take 1 (1 : wallace (gromit (...) ) ) ]
-- reduces to [0, 1 ]
Один из обоих пиров должен «начать» обсуждение, поэтому начальное значение предоставлено wallace
.
Также обратите внимание на шаблон ~ before gromit
: это говорит Haskell, что содержимое аргумента list не нужно сокращать - если он видит, что это список, этого достаточно. Об этом есть хорошая тема в вики-книге на Haskell (ищите "Lazy Pattern Matching).