首页 > 解决方案 > 阅读 int 孤立地工作,但如何让它在这个脚本中工作?

问题描述

当我尝试调用 read 来读取Int32时,它在 GHCi 中工作:

$ ghci
GHCi, version 8.4.4: http://www.haskell.org/ghc/  :? for help
Prelude> import Data.Int
Prelude Data.Int> let fooInt32 :: Int32; fooInt32 = read "6531"
Prelude Data.Int> :t fooInt32
fooInt32 :: Int32
Prelude Data.Int> fooInt32
6531

但是,在我的应用程序中,我收到此错误(使用包装读取以获得更好的错误消息):

readInt32.hs:  read error, reading: '6531'
CallStack (from HasCallStack):
  error, called at /home/brandon/workspace/ProjectGists/Haskell/ReadInt32/readInt32.hs:27:9 in main:Main

这是一个独立的堆栈脚本,它举例说明了错误:

#!/usr/bin/env stack
-- stack --resolver lts-13.14 script
{-# LANGUAGE OverloadedStrings #-}

import           Data.Int
import           Data.Maybe                       (fromJust, isJust, listToMaybe)
import           Data.String                      (IsString(..))
import           Data.Text                        (Text, pack, splitOn, unpack)
import           Data.Time.Calendar               (Day(..))
import           Data.Time.Clock                  (UTCTime(..))
import           Data.Typeable

newtype CowMark = CowMark {unCowMark :: Int32}
  deriving (Eq, Ord, Read, Show, Typeable)

newtype TableName = TableName {unTableName :: Text}
  deriving (Eq, Ord, Read, Show)

instance IsString TableName where
  fromString str = TableName $ pack str

type CowRecordKey = (TableName, CowMark, UTCTime)

read' :: Read a => String -> a
read' s = case reads s of
  [(x,"")] -> x
  _  -> error $ " read error, reading: '" ++ s ++ "'"

rep2Key :: String -> Maybe CowRecordKey
rep2Key strKey = do
  splList <- return $ splitOn "_" (pack strKey)
  (tblName, mrkStr, timeStr) <- head3 splList
  miInt <- read' (unpack mrkStr)
  timeOut <- read (unpack timeStr)
  return $ (TableName $ tblName, CowMark miInt, timeOut)
  where
    head3 :: [a] -> Maybe (a, a, a)
    head3 list@(_:x2:xs) = do
      mx1 <- listToMaybe list
      mx2 <- listToMaybe (x2:xs)
      mx3 <- listToMaybe xs
      return (mx1, mx2, mx3)
    head3 _ = Nothing

cowRecKey1 :: CowRecordKey
cowRecKey1 = (
    TableName "SxRecord"
  , CowMark 6531
  , UTCTime (ModifiedJulianDay 3234) 0
  )

cowRecKeyStr1 :: String
cowRecKeyStr1 = "SxRecord_6531_1867-09-25 00:00:00"

main = do
  key1 <- return $ rep2Key cowRecKeyStr1
  print key1

不知道该怎么做。我也尝试过注释miInt :: Int32以查看是否有帮助,但没有。

标签: haskell

解决方案


我已read'在您的脚本中使用预期的类型进行了注释:

read' :: String -> Int32
read' s = case reads s of
  [(x,"")] -> x
  _ -> error $ " read error, reading: '" ++ s ++ "'"

并立即得到一个错误:

• Couldn't match expected type ‘Maybe Int32’
              with actual type ‘Int32’
• In a stmt of a 'do' block: miInt <- read' (unpack mrkStr)

实际上,do块 inrep2Key是在Maybe上下文中运行的,所以该行

miInt <- read' (unpack mrkStr)

绑定miInt :: Int32,但右边的表达式具有类型Maybe Int32。这就是为什么注释miInt本身并没有指出问题所在。

如果您想使解析失败 (?),请更改read'为返回 a Maybe,如下所示:

read' :: Read a => String -> Maybe a
read' s = case reads s of
  [(x,"")] -> Just x
  _  -> Nothing

如果要保留error行为(和read'签名),或者对于返回纯值的任何其他函数,可以将行更改rep2Key

let miInt = read' (unpack mrkStr)

HeremiInt绑定到右侧的值而不调用>>=,因此它应该是相同的类型(Int32没有Maybe)。

Hoogle搜索显示,最后一个函数作为Text.Read.readMaybe存在于 Prelude 中。


推荐阅读