Haskell: изменение значения по определенному индексу массива - PullRequest
2 голосов
/ 27 мая 2019

Новый для Хаскелла.Я создал массив char, и я пытаюсь найти лучший способ изменить данные в этом массиве с учетом определенного индекса.

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

import System.Random
import Control.Monad
import Data.Array
import Data.List

modifyArray :: Array Int Char -> Int -> IO (Array Int Char)
modifyArray arr i =
    if i > 0 then
        if i `mod` 102 == 1 then do
            (MODIFY ARRAY AT INDEX:i to equal ' ')
        else modifyArray arr (i-1)
    else arr   

Ответы [ 2 ]

4 голосов
/ 27 мая 2019

На самом деле вам не нужно изменять массив. Просто заставьте свою функцию создать новый массив, в котором есть нужное вам изменение, например:

modifyArray :: Array Int Char -> Int -> Array Int Char
modifyArray arr i =
    if i > 0 then
        if i `mod` 102 == 1 then
            arr // [(i, ' ')]
        else modifyArray arr (i-1)
    else arr   

Data.Array включает в себя оператор //, что означает «взять массив слева, применить изменения справа и вернуть результат». Кроме того, поскольку эта функция не выполняет IO, нет необходимости использовать «do» или иметь IO в сигнатуре типа.

2 голосов
/ 28 мая 2019

Если вы планируете обновить массив только несколько раз, вы можете использовать оператор (//) :: Ix i => Array i e -> [(i, e)] -> Array i e , как говорит @ JosephSible .

Как, однако, обсуждается в вопрос " Как быстро Data.Array? " , это не очень эффективно, если вы хотите регулярно обновлять массив :

Обратите внимание, что //, вероятно, O (n) , хотя, поскольку он должен проходить по списку (точно так же, как это делает императивная программа).Если вам нужна большая мутация, вы можете использовать MArray или MVector.

Таким образом, это означает, что для больших массивов обновление массива может занять некоторое время, так каккаждое обновление приводит к созданию копии исходного массива и изменению этого конкретного значения.

IOArray - это определенный типтаких MArray.Таким образом, мы можем определить modifyArray с помощью writeArray :: (MArray a e m, Ix i) => a i e -> i -> e -> m ():

modifyArray :: <b>IOArray</b> Int Char -> Int -> IO (<b>IOArray</b> Int Char)
modifyArray arr idx | i < 0 = return arr
                    | mod i 102 == 1 = <b>writeArray arr idx ' '</b> >> return arr
                    | otherwise = modifyarr arr idx

Обратите внимание, что здесь возвращать массив не нужно, по сути IOArrayможет рассматриваться как ссылка на изменяемый массив, поэтому после операции writeArray arr ссылается на измененный массив.Если вы используете это в более крупной операции IO, то после modifyArray этот массив будет изменен.

Здесь вы используете цикл для получения наибольшего индекса i, который имеет div i 102 == 1 и равенменьше или равно начальному индексу.Однако вы можете улучшить это, вычтя результат по модулю:

modifyArray :: IOArray Int Char -> Int -> IO (IOArray Int Char)
modifyArray arr idx | i < 0 = return arr
                    | otherwise = writeArray arr <b>(idx - mod (idx-1) 102)</b> ' ' >> return arr
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...