Haskell получает значения из домена IO - PullRequest
0 голосов
/ 01 сентября 2018

После прочтения книг на Haskell я немного растерялся (или просто забыл), как получить значение из домена IO в «мир Haskell» для его анализа, например:

fGetSeq = do
  input <- sequence [getLine, getLine, getLine]
  fTest input
  mapM_ print input

fTest =  map (read :: String -> Int)

Очевидно, что компилятор жалуется. Couldn't match [] with IO. Есть простое эмпирическое правило для передачи значений между «мирами», или это просто мое плохо, если опустить типигс?

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

получить значение из домена ввода-вывода в мир Haskell

Вы используете оператор связывания: (>>=) :: Monad m => m a -> (a -> m b) -> m b.

Если m = IO, то это выглядит так: (>>=) :: IO a -> (a -> IO b) -> IO b.

Как видите, функция с типом a -> IO b обращается к a без IO.

Так, учитывая значение в монаде IO, например, getLine :: IO String

getInt :: IO Int
getInt = getLine >>= (\s -> return (read s))

Здесь s :: String, read :: String -> Int и return :: Int -> IO Int.

Вы можете переписать это, используя do-block:

getInt :: IO Int
getInt = do
  s <- getLine
  return (read s)

Или используйте стандартную библиотечную функцию, которая делает именно это:

getInt :: IO Int
getInt = readLn

Что касается вашего примера, вы можете немедленно исправить это с помощью let-привязки:

foo :: IO ()
foo = do
  input <- sequence [getLine, getLine, getLine]
  let ints = bar input
  mapM_ print ints

bar :: [String] -> [Int]
bar = map read

Или вы можете реструктурировать его для использования getInt, как определено выше:

foo :: IO ()
foo = sequence [getInt, getInt, getInt] >>= mapM_ print
0 голосов
/ 01 сентября 2018

Суть записи do в том, что каждое значение монадического действия в ней (справа от <- s или на их собственной строке) должно принадлежать одной и той же монаде . Это

 do {
      x <- ma ;          -- ma :: m a     x       :: a
      y <- mb ;          -- mb :: m b     y       :: b   ( with the same m! )
      return (foo x y)   --               foo x y :: c     return (foo x y) :: m c
    }                    --    :: m                  c

Теперь, поскольку sequence [getLine, getLine, getLine] :: IO [String], это означает, что ваш блок do принадлежит IO.

Но вы можете обращаться со значениями по-своему, когда вы их получили:

fGetSeq :: IO ()
fGetSeq = do
  inputs <- sequence [getLine, getLine, getLine]   -- inputs :: [String]
  let vals = fTest inputs
  mapM_ print vals

fTest :: [String] -> [Int]
fTest =  map (read :: String -> Int)

-- or just
fGetSeq1 = do
  inputs <- sequence [getLine, getLine, getLine]
  mapM_ print ( fTest inputs )

-- or
fGetSeq2 = do { vals <- fTest <$> sequence [getLine, getLine, getLine] ;
                mapM_ print vals }   -- vals :: [Int]

-- or even (with redundant parens for clarity)
fGetSeq3 = mapM_ print =<< ( fTest <$> sequence [getLine, getLine, getLine] )
    --   = mapM_ print . fTest =<< sequence [getLine, getLine, getLine]

Сущность Монады заключается в наложении чистых вычислений «мира Хаскеля» между потенциально нечистыми, «эффективными» вычислениями.

Итак, мы уже в чистом мире Хаскелла, с левой стороны от этого <-. И снова inputs :: [String]. Чистая стоимость.

...