Лучший ответ, который я могу придумать, заключается в том, что вам, вероятно, следует изменить свою программу так, чтобы ваши типы представляли то, что вы хотите.В частности, когда я смотрю на ваш код, кажется, что у вас есть (или, по крайней мере, вы думаете / у вас нет, но вы написали не ту программу):
- Каждый
[[(Int,Int,Int)]]
представляет собой списокформа [xs]
- Каждый
(Int,Int,Int)
является либо (0,0,0)
, либо (1,1,1)
Во-первых, я запишу решение вашей проблемы, как указано.Во-вторых, я покажу вам, как создавать типы, которые представляют состояние мира (и не позволяют вам представлять недопустимые состояния).
renderThing (0,0,0) = ' '
renderThing (1,1,1) = '█'
renderState = map (map renderThing)
Давайте кратко опишем это.Первые две строки определяют частичную функцию для выполнения функции int-triple-to-char, как описано в родительском элементе.
Третья строка определяет требуемую функцию.Давайте прочитаем его слева направо:
- К
renderState
(который будет иметь тип [[(Int,Int,Int)]] -> [[Char]]
): - Примените
map renderThing :: [(Int,Int,Int)] -> [Char]
к каждому элементу списка, переданному какinput - Чтобы выполнить эту функцию, примените
renderThing
к каждому элементу внутреннего списка (я предполагаю, что это строка)
К сожалению, ваша программа будетсбой, если вы когда-нибудь нарушите свой неявный инвариант, что любой (Int,Int,Int)
равен либо (0,0,0)
, либо (1,1,1)
.Один лучший тип может быть (Bool,Bool,Bool)
, поскольку каждый элемент может иметь только одно из двух значений.Еще один способ сделать это:
data Thing = White | Black
Есть два способа вставить это в вашу программу.Либо используйте хорошие типы везде, чтобы компилятор мог убедиться, что вы никогда не попадете в непредвиденное состояние, либо у вас могут быть функции преобразования, которые могут иметь ошибки:
renderableBoard :: [[(Int,Int,Int)]] -> Either String [[Thing]]
renderableBoard = mapM (mapM convertOne) where
convertOne (0,0,0) = White
convertOne (1,1,1) = Black
convertOne x = "cannot concert to thing: " ++ show x