Как изменить это на время l oop in Haskell? - PullRequest
3 голосов
/ 23 марта 2020

Haskell сложно! До сих пор я понял, что могу сделать следующее для имитации for-l oop в Haskell, чтобы получить список чисел от пользователя:

myList <- sequence [putStr "Enter an integer: " >> (
    \s -> read s :: Int) <$> getLine | t <- [1..5]]

Отлично! Итак, myList содержит пять целых чисел, которые я ввел. Большой! Но вот в чем подвох. Вместо for-l oop, который повторяется пять раз (или любое конечное число раз), как я могу преобразовать вышеприведенное в эквивалентное время, пока-l oop?

Итак, я думаю об этом, но, к сожалению, это не сработает. Есть ли какой-нибудь "волшебный" способ заставить его работать?

takeWhile (\x -> x > 0) $ sequence [putStr "Enter an integer: " >> (
    \s -> read s :: Int) <$> getLine | t <- [1..]]

Проблема в том, что (\x -> x > 0) работает с Ints. (Или любой тип Num.) Но то, что приходит из этого списка - это действительно куча IO Ints. x > 0 возвращает Bool. Мне нужна функция, которая возвращает IO Bool? Я немного растерялся. Может кто-нибудь указать мне путь к Haskell просветлению ?! Изучать это самостоятельно не совсем просто !!! Большое вам спасибо !!!

Ответы [ 2 ]

7 голосов
/ 23 марта 2020

Вы не можете написать эту программу с sequence бесконечного списка операций ввода-вывода. Любые операции, которые вы выполняете «вне» последовательности, не смогут проверить ее содержимое, и любые операции внутри последовательности не смогут остановить ее продолжение.

Вместо этого вы должны написать действие ввода-вывода, которое читает Int проверяет его и решает, продолжать или прекратить в это время.

positiveInts :: IO [Int]
positiveInts = do
  putStr "Enter an integer: "
  i <- readLn
  if i <= 0
    then pure []
    else (i:) <$> positiveInts
0 голосов
/ 23 марта 2020

@ Амаллой ответил отлично. Это вид условного упорядочения.

Возможно, мы можем попытаться обобщить его дальше, придумав takeWhileM (в основном, условное упорядочение), которое упорядочивает только начальную часть бесконечно длинного списка действий, в то время как предикат удовлетворяет.

takeWhileM :: Monad m => (a -> Bool) -> [m a] -> m [a]
takeWhileM f (a:as) = a >>= \n -> if f n then (n:) <$> takeWhileM f as
                                         else pure []

Так что для этого конкретного случая я запускаю его как

λ> takeWhileM (> 0) . repeat $ putStr "Enter an integer:" >> readLn
Enter an integer:1
Enter an integer:2
Enter an integer:3
Enter an integer:4
Enter an integer:5
Enter an integer:0
[1,2,3,4,5]
...