Haskell中do块返回值方法及相关代码问题咨询
关于Haskell中
parseMessage函数的问题解答 首先纠正一个核心错误:你的parseMessage是纯函数,返回类型是LogMessage,完全不需要用do块——do语法是用于Monad上下文(比如IO、Maybe这类带上下文的类型)的,纯函数直接写逻辑就行。
问题1:字符串比较的正确性
你当前的写法有类型错误:
take 1 brokenLine返回的是[String](因为words string输出字符串列表,take 1取第一个元素组成的单元素列表),而你要比较的"E"是String类型,两者类型不匹配,编译会直接报错。- 正确的做法是取列表的第一个元素,比如用
head brokenLine(注意:如果输入字符串为空或拆分后无元素,head会触发运行时错误,后续可以用模式匹配优化),此时label是String类型,用==比较字符串相等是完全正确的。
问题2:if-else中返回构造函数
首先,Error/Info/Warning作为LogMessage的构造函数,应该是带参数的(比如常见的定义是data LogMessage = Info String | Warning String | Error Int String | Unknown),你直接写Error会因为缺少参数报错。比如要返回Info类型,需要传入消息内容,比如Info (unwords (tail brokenLine))(把拆分后除了标签的部分拼接成消息)。
另外,原代码里的return Unknown也是错误的——return是Monad类型的函数,纯函数里直接写Unknown即可。
Guard语法中加入let绑定的写法
你可以用where从句或者let...in两种方式来处理brokenLine和label的绑定:
方式1:使用where从句
parseMessage :: String -> LogMessage parseMessage string | label == "I" = Info (unwords rest) | label == "W" = Warning (unwords rest) | label == "E" = Error (read levelStr) (unwords restMsg) -- 假设Error需要级别参数 | otherwise = Unknown where brokenLine = words string label = head brokenLine -- 根据构造函数需求拆分参数,比如Error需要级别和消息 (levelStr:restMsg) = tail brokenLine rest = tail brokenLine -- 对应Info/Warning的消息部分
方式2:使用let...in包裹逻辑
parseMessage :: String -> LogMessage parseMessage string = let brokenLine = words string label = head brokenLine rest = tail brokenLine in | label == "I" = Info (unwords rest) | label == "W" = Warning (unwords rest) | label == "E" = Error (read (head rest)) (unwords (tail rest)) | otherwise = Unknown
更安全的优化写法:模式匹配
用模式匹配代替head/tail可以避免空列表导致的运行时错误,代码更健壮:
parseMessage :: String -> LogMessage parseMessage string = case words string of ("I":msgParts) -> Info (unwords msgParts) ("W":msgParts) -> Warning (unwords msgParts) ("E":levelStr:msgParts) -> Error (read levelStr) (unwords msgParts) _ -> Unknown
内容的提问来源于stack exchange,提问作者Harry Zhou
相关产品推荐
相关产品推荐

