Вот способ, который не требует ввода-вывода, вместо этого полагаясь на лень, и ваш программист угадывает, какая «сторона» условия встречается чаще. Просто чтобы было с чем поиграть, вот немного медленная функция, которая проверяет, является ли число кратным 10. Детали этой функции не важны, не стесняйтесь пропустить ее, если что-то не имеет смысла. Я также собираюсь включить отчеты о времени; вы увидите, почему позже.
> isSpecial :: Int -> Bool; isSpecial n = last [1..10000000] `seq` (n `mod` 10 == 0)
> :set +s
(Добавляйте один 0
каждые пять лет.)
Теперь идея будет такой: вместо понимания вашего списка мы будем использовать partition
, чтобы разделить список на две части, элементы, которые соответствуют предикату, и те, которые не соответствуют. Мы напечатаем тот из них, у которого больше элементов, чтобы мы могли следить за прогрессом; к тому времени, когда он будет полностью напечатан, другой будет полностью оценен, и мы сможем проверить его, как захотим.
> :m + Data.List
> (matches, nonMatches) = partition isSpecial [1..20]
(0.00 secs, 0 bytes)
> nonMatches
[1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19]
(12.40 secs, 14,400,099,848 bytes)
Очевидно, я не могу отобразить это через StackOverflow, но когда я сделал вышеописанное, числа в списке nonMatches
медленно появлялись на моем терминале одно за другим, давая довольно хороший индикатор того, где в списке он в данный момент думал. И теперь, когда вы печатаете matches
, полный список доступен более или менее мгновенно, как вы можете видеть по отчету о времени (т.е. не через очередное 12-секундное ожидание):
> matches
[10,20]
(0.01 secs, 64,112 bytes)
Но будьте осторожны!
Важно, чтобы matches
и nonMatches
имели типы, которые не являются полиморфными классами типов (т. е. не имеют типов, начинающихся с Num a => ...
или какого-либо другого ограничения). В приведенном выше примере я добился этого, сделав isSpecial
мономорфным, что вынуждает matches
и nonMatches
быть такими же, но если ваш isSpecial
полиморфен, вы должны указать сигнатуру типа для matches
или nonMatches
, чтобы предотвратить эту проблему.
Таким образом, все списки nonMatches
и matches
будут реализованы в памяти. Это может быть дорого, если первоначальный разделяемый список очень длинный. (Но до, скажем, пары сотен тысяч Int
s для современных компьютеров не так уж и много.)
person
Daniel Wagner
schedule
25.11.2019
IO
, которое перебирает все числа от 1 до 10000, сверяет каждое сisSpecial
и распечатывает свой прогресс на терминале. Это то, о чем вы говорите? - person Robin Zigmond   schedule 26.11.2019isSpecial_Verbose
, который что-то говорит каждый раз, когда он вызывается? - person Student   schedule 26.11.2019isSpecial
— это функция отInt
доBool
. Как мне сделать так, чтобы его вывод был какBool
, так иIO()
? @РобинЗигмонд - person Student   schedule 26.11.2019IO ()
, которое используетisSpecial
(и прокручивать соответствующие числа) - person Robin Zigmond   schedule 26.11.2019verbosified :: (a->b) -> IO()
и применить ее кisSpecial
? Мой вопрос все еще там: мне нужна функцияisSpecial
, чтобы сообщить свои логические результаты. Как я могу сохранить это, делая его подробным? - person Student   schedule 26.11.2019tellMeResult :: Int -> IO (); tellMeResult n = putStrLn $ "Testing " ++ show n ++ " - it's " ++ (if isSpecial n then "special" else "not special")
. Затем выполните это для всех чисел от 1 до 1000 (например, сmapM
). - person Robin Zigmond   schedule 26.11.2019