当前位置:  开发笔记 > 开发工具 > 正文

是否有可能在Haskell中筑巢?

如何解决《是否有可能在Haskell中筑巢?》经验,为你挑选了4个好方法。

Haskell新手在这里,试图编写代码来解析数学表达式.码:

isDigit :: Char -> Bool
isDigit c = c >= '0' && c <= '9'

parseNumber :: String -> Maybe (String, String)
parseNumber [] = Just ("", "")
parseNumber (h:ls)
    | isDigit h
        | p == Nothing = Just([h], ls)      -- Digit found    <<< ERROR!!
        | otherwise = Just (h:fst d, snd d) -- Ends in a digit
    | h == '.'
        | p == Nothing = Nothing                                -- Ends in a point
        | not ('.' `elem` (snd d)) = Just (h:(fst d), snd d)    -- We don't want multiple dots
    | otherwise = Nothing       -- Not a number, stop looking!
    where 
        p = parseNumber ls
        Just d = parseNumber ls -- Float version of p. Not used if p is Nothing  

此函数应该采用以数字开头的字符串,并返回与表达式其余部分分开的数字.例:

parseNumber"123.0 + 2"

("123.0","+ 2")

我认为这个嵌套的守卫的语法读得非常好,但它不起作用.对于标记的行,错误读取:

输入"|"时解析错误

Haskell中不允许使用链式防护装置吗?或者我是以某种方式错误地写这个?另外,我有什么替代方法可以简单地链接逻辑?



1> Thomas M. Du..:

不,但如果您愿意,可以使用案例:

parseNumber :: String -> Maybe (String, String)
parseNumber [] = Just ("", "")
parseNumber (h:ls)
    | isDigit h =
         case () of
           () | p == Nothing = Just([h], ls)
              | otherwise = Just (h:fst d, snd d) -- Ends in a digit
    | h == '.' =
         case () of
           () | p == Nothing = Nothing
              | not ('.' `elem` (snd d)) = Just (h:(fst d), snd d)
    | otherwise = Nothing
    where 
        p      = parseNumber ls
        Just d = parseNumber ls

或者,如果以类似方式工作,则多路(if True | p1 -> b ; | p2 -> c).



2> augustss..:

不,你不能.我们都想要它,但没有人能够提出合理的语法.



3> user2407038..:

当你的函数变得非常复杂并且你不能仅仅使用守卫来支持逻辑时,可以考虑使用抽象控制函数来编写函数:

import Control.Applicative 
import Control.Monad 

isDigit :: Char -> Bool
isDigit c = c >= '0' && c <= '9'

parseNumber :: String -> Maybe (String, String)
parseNumber [] = return ("", "")
parseNumber (h:ls) = dig <|> dot where -- h is either a digit or a dot
  p = parseNumber ls 
  dig = do 
    guard (isDigit h)                                 -- ensure h is a digit
    fmap (\(ds,r) -> (h:ds,r)) p 
      <|> return ([h],ls)  -- the alternative between two computations
                           -- either the tail is parsed and h prepended to the result
                           -- or the digit is returned by itself                         
  dot = do 
    guard (h == '.')             -- ensure h is a dot
    (ds,r) <- p                  -- parse the tail
    guard $ not $ '.' `elem` ds  -- ensure there is no dot in the tail
    return (h:ds,r)              -- result

这里使用了Monad,FunctorMonadPlus实例Maybe来实现的分析逻辑.实际上,这个函数推广到了类型MonadPlus m => String -> m (String, String)- 这里没有实际使用Maybe构造函数.

该功能也易于阅读.在带有警卫的版本中发生的情况更为明显.



4> HTNW..:

最近的GHC现在有MultiWayIf

{-# LANGUAGE MultiWayIf #-}

parseNumber :: String -> Maybe (String, String)
parseNumber [] = Just ("", "")
parseNumber (h:ls)
  | isDigit h = if
    | p == Nothing -> Just ([h], ls)
    | otherwise    -> Just (h:fst d, snd d)
  | h == '.'  = if
    | p == Nothing             -> Nothing
    | not ('.' `elem` (snd d)) -> Just (h:(fst d), snd d)
  | otherwise = Nothing
  where p@(~(Just d)) = parseNumber ls

但这最好以不同的方式写,没有偏见。

{-# LANGUAGE MultiWayIf #-}

parseNumber :: String -> Maybe (String, String)
parseNumber [] = Just ("", "")
parseNumber (h:ls)
  | isDigit h = if
    | Nothing <- p -> Just ([h], ls) -- PatternGuards, on by default
    | Just d  <- p -> Just (h:fst d, snd d)
  | h == '.'  = if
    | Nothing <- p                         -> Nothing
    | Just d  <- p, not ('.' `elem` snd d) -> Just (h:(fst d), snd d)
  | otherwise = Nothing
  where p = parseNumber ls

而且您最好使用maybe

parseNumber :: String -> Maybe (String, String)
parseNumber "" = Just ("", "")
parseNumber (h:hs)
  | isDigit h = maybe (Just ([h], hs)) (\(num, rest') -> Just (h:num, rest')) rest
  | h == '.'  = maybe Nothing (\(num, rest') -> if '.' `elem` num then Nothing
                                                else Just (h:num, rest')
                              ) rest -- This logic is a bit wonky; it doesn't really work
  | otherwise = Nothing
  where rest = parseNumber hs

推荐阅读
手机用户2502852037
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有