Функция, которая принимает массив символов и возвращает объединенную строку.Haskell - PullRequest
4 голосов
/ 27 мая 2019

тьфу ... борется с хаскеллом. Попытка реализовать GOL Конвея и создать случайную игровую доску. Вот где я нахожусь.

У меня есть функция для рандомизации каждого квадрата в массиве и функция для создания массива символов с использованием функции рандомизации для представления моей игровой доски.

Сейчас я пытаюсь создать функцию: showBoard, которая перебирает массив и объединяет каждый символ в строку, которую я могу распечатать в своем main.

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

randomBoard = do
    f1 <- randomIO :: IO Int
    if(f1 `mod` 2) == 0
        then return  '*'
        else return  ' '

boardArray :: IO (Array Int Char)
boardArray = listArray (0, 99) <$> replicateM 100 randomBoard


showBoard :: IO (Array Int Char) -> Int -> String -> String
showBoard arr i str = do
    if i > 0
       then showBoard arr (i-1) (str ++ (arr ! i))
       else return str

main :: IO ()
main = 
let board = showBoard boardArray 100 ""
    in
        do
            putStr board

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

1 Ответ

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

Несколько проблем:

  1. Невозможно написать функцию, которая берет IO чего-либо и использует ее для возврата чего-то, чего нет в IO. Измените showBoard на Array Int Char без оболочки IO и удалите из него do и return.
  2. Поскольку ваш массив начинается с нуля, измените arr ! i на arr ! (i - 1).
  3. arr содержит Char с, а не String с, поэтому используйте [] вместо () вокруг индексации, чтобы превратить его в String.
  4. Поскольку мы заставили showBoard принять значение без IO, используйте <- в main, чтобы получить необходимое нам внутреннее значение.

Вот результат всех этих изменений:

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

randomBoard = do
    f1 <- randomIO :: IO Int
    if(f1 `mod` 2) == 0
        then return  '*'
        else return  ' '

boardArray :: IO (Array Int Char)
boardArray = listArray (0, 99) <$> replicateM 100 randomBoard


showBoard :: Array Int Char -> Int -> String -> String
showBoard arr i str =
    if i > 0
       then showBoard arr (i-1) (str ++ [arr ! (i - 1)])
       else str

main :: IO ()
main = do
    randomArray <- boardArray
    let board = showBoard randomArray 100 ""
    putStr board

Кроме того, способ реализации showBoard, хотя и работает, особенно неэффективен. Вы должны избегать рекурсивных действий, которые выглядят как x ++ [y], поскольку это квадратично медленно. Кроме того, похоже, что ваша функция печатает элементы, начиная с конца и опускаясь до 0, а не начиная с 0 и доходя до конца. Вот новая версия, которая исправляет обе эти вещи сразу:

showBoard :: Array Int Char -> Int -> String -> String
showBoard arr i str =
    if i > 0
       then showBoard arr (i-1) ((arr ! (i - 1)) : str)
       else str

Использование :, где это возможно, намного эффективнее, чем всегда использование ++.

Вы можете упростить еще больше, не имея вообще showBoard, и вместо этого используйте elems (из Data.Array):

main :: IO ()
main = do
    randomArray <- boardArray
    let board = elems randomArray
    putStr board
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...