Ответ 1
Ваш первый пример строгий на карте. Следующее просматривает print "1"
, затем запускает его, и программа на самом деле печатает 1. Конечно, это требует оценки m
.
main = do let m = Map.fromList [(1, print "1")]
val <- m ! 1
return val
Вероятно, вы должны написать что-то, что только читает карту. Следующее не является строгим, поскольку val
не используется в выражении case.
main = do let m = Map.fromList [(1, print "1")]
let val = m ! 1
return val
Второй пример строгий, потому что он проверяет, удалось ли выполнить результат lookup
, чтобы решить, как завершить выполнение блока do. Это требует чтения карты. Это эквивалентно:
do m <- ask
case lookup key m of
Nothing -> fail "oh noes"
Just x -> doSomething x
Проблемы строгости отладки
Оценка всегда принудительно выполняется выражением case или некоторыми встроенными операторами, такими как +
для целых чисел. Если вы подозреваете, что ваша программа терпит неудачу, потому что значение принудительно до этого доступно, вам нужно будет узнать, какое значение принудительно и где оно принудительно.
Какое значение было принудительно?
В этом виде ошибок программа пытается оценить выражение, зависящее от результата собственной оценки. Вы можете использовать trace
для отслеживания того, какое выражение оценивается. В этой проблеме, похоже, что значение m
принудительно, поэтому используйте trace
для печати сообщения непосредственно перед его вычислением:
do m1 <- ask
let m = trace "Using m" m1
...
Если "Использовать m" - последний выход из вашей программы (до <<loop>>
), вы приближаетесь к ошибке. Если он не выводится, то m
не оценивается, поэтому проблема находится в другом месте. Если что-то следует за этой строкой на выходе, то программа продолжает выполнение, а ошибка возникает позже, поэтому проблема должна быть где-то еще.
Где это было принудительно?
Это говорит о том, что оценка прошла, по крайней мере, до того, как остановить. Но как далеко он прошел? Проблема на самом деле произошла намного позже? Чтобы убедиться в этом, попробуйте положить trace
на то, что будет оцениваться позже. Мы знаем, что m
оценивается для того, чтобы решить, какая ветвь maybe
выполняется, поэтому мы можем положить trace
в эти точки.
do m1 <- ask
let m = trace "Using m" m1
maybe (trace "Used m" $ fail "oh noes")
(\x -> trace "Used m" $ doSomething x)
(lookup key m)
Если вы видите "Использование m", а затем "Используется m" на выходе, вы знаете, что оценка m
завершена, и программа продолжалась. Если вы видите только "Использование m", программа останавливается между этими точками. В этом конкретном случае вы не должны видеть "Used m", потому что maybe
заставляет evaulation m
и вызывает <<loop>>
.