Сложность добавления элементов в список при использовании ввода-вывода в Haskell - PullRequest
0 голосов
/ 05 февраля 2012

У меня есть список целых чисел, мне нужно добавлять элементы в него в разное время.

let xs =[]::[Int]

обычно добавление элементов к этому будет выглядеть так:

1:xs

но при использовании IO в функции он, похоже, не работает в блоке do и выдает ошибки, а

let xs = [1]
let xs=(2:xs)

приводит к бесконечному списку, подобному [1,2,2,2,2, .....] Что я могу сделать, чтобы исправить это?

Ответы [ 4 ]

7 голосов
/ 05 февраля 2012

У вас, похоже, есть фундаментальное недопонимание относительно списков в Haskell. Списки всегда неизменны, поэтому невозможно добавить новые элементы в существующий список. То есть Вы можете создавать только новые списки.

Таким образом, соответственно, оператор a:b никогда не добавляет элемент в список, а создает новый список, где a - первый элемент, за которым следует существующий список b.

Когда вы говорите:

let xs = 2 : xs

Вы говорите, что xs - это список, в котором первый элемент равен 2, а остальная часть списка - это xs, что логически приводит к бесконечному списку из 2. В контексте этого вопроса не имеет значения, находитесь ли вы в монаде IO или нет.

Итак, учитывая вышесказанное, вам нужно сделать что-то вроде

let xs1 = [1]
let xs2 = 2:xs1
let xs3 = 3:xs2

Но, конечно, это то же самое, что просто сделать

let xs3 = [3,2,1]

Так что вам действительно нужно дать больше контекста о том, какой список вы хотите создать и почему.

5 голосов
/ 05 февраля 2012

В Haskell привязки let по умолчанию рекурсивны.Таким образом, два xs во второй строке относятся к себе.Решение состоит в том, чтобы не затенять привязку xs:

let xs = [1]
let xs' = 2:xs

Помните, что Haskell не допускает мутации.Таким образом, вторая let привязка не означает , что означает изменение значения xs - это означает создание новой переменной, которая также называется xs.

Просто дляуточнить: xs' полностью отделен от xs.Haskell позволяет использовать ' в именах переменных.xs' здесь может быть так же легко xs2.' произносится как «простое» (например, exes prime) и взято из математики, где такие вещи, как x, x' и x'' являются общими.

Примечание: : добавляет к списку;добавление означает помещение элемента в конец.

Кроме того, ваш let xs = 2:xs даст [2,2,2...], а не [1,2,2,2...].

2 голосов
/ 05 февраля 2012

Для полноты, если вы действительно хотите «назначить» императивно в монаде IO (к чему вы, похоже, стремились), вы можете это сделать. Вы бы использовали изменяемую ячейку («ссылка»); который в монаде IO, будет IORef:

import Data.IORef

do xs <- newIORef [1]
   temp <- readIORef xs
   writeIORef xs (2 : temp)

Тем не менее, это было бы крайне неубедительно, и вы почти никогда не хотели бы писать такие вещи.

0 голосов
/ 05 февраля 2012

Не сделать свой список рекурсивным?

let xs = [1]
let foo=(2:xs) -- non-recursive
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...