Haskell 有可能在哈斯克尔安顿警卫吗?

Haskell 有可能在哈斯克尔安顿警卫吗?,haskell,Haskell,Haskell是这里的新手,正在尝试编写解析数学表达式的代码。 代码: isDigit::Char->Bool isDigit c=c>='0'&&c Maybe(字符串,字符串) parseNumber[]=仅(“,”) 密码(h:ls) |isDigit h |p==Nothing=Just([h],ls)--找到数字No,这是不可能的。为什么不把它写成线性呢 isDigit :: Char -> Bool isDigit c = c >= '0' && c &l

Haskell是这里的新手,正在尝试编写解析数学表达式的代码。 代码:

isDigit::Char->Bool
isDigit c=c>='0'&&c Maybe(字符串,字符串)
parseNumber[]=仅(“,”)
密码(h:ls)
|isDigit h

|p==Nothing=Just([h],ls)--找到数字No,这是不可能的。为什么不把它写成线性呢

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

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

main = print $ parseNumber "123.0 + 2"
isDigit::Char->Bool
isDigit c=c>='0'&&c Maybe(字符串,字符串)
parseNumber[]=仅(“,”)
密码(h:ls)
--找到数字
|isDigit h&&p==Nothing=Just([h],ls)
--以数字结尾
|isDigit h=Just(h:fst d,snd)
--到头来
|h=='.&&p==Nothing=Nothing
--我们不想要多个点
|h=='.&¬('.'elem`(snd))=Just(h:(fst d),snd)
--不是数字,别看了!
|否则=没有
哪里
p=解析数
只是d=parseNumber ls——p的浮点版本。如果p为空,则不使用
main=打印$parseNumber“123.0+2”

如果你的警卫介入太多,这可能表明你需要提取一个函数。

否,但如果你愿意,你可以使用用例:

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

另一方面,多路径如果以类似的方式工作(<代码>如果真的是p1->b;p2>> c>代码>)

当你的函数变得非常复杂,你不能支持仅仅用守护程序实现的逻辑时,考虑用抽象的控制函数编写函数代替:

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
导入控件。应用程序
进口管制
isDigit::Char->Bool
isDigit c=c>='0'&&c Maybe(字符串,字符串)
parseNumber[]=返回(“,”)
parseNumber(h:ls)=数字点,其中--h是数字或点
p=解析数
挖=做
保护(isDigit h)——确保h是一个数字
fmap(\(ds,r)->(h:ds,r))p
return([h],ls)--两次计算之间的替代方法
--要么解析尾部,要么在结果前面加h
--或者数字本身返回
dot=do
保护(h=='。)--确保h是一个点
(ds,r)String->m(String,String)
-这里没有实际使用
可能
构造函数

该函数也易于阅读。更明显的是,在有警卫的版本中发生了什么

可以使用
锁紧防护装置。这与fjarri的答案中的
&
基本相同,但在模式保护方面更通用

不可能的是筑巢守卫。在你的例子中,这只在第一条中需要。你可以写

parseNumber (h:ls)
    | isDigit h
       = if isNothing p
           then Just ([h], ls)        -- Digit found    <<< ERROR!!
           else Just (h:fst d, snd d) -- Ends in a digit
    | h == '.'
    , not ('.' `elem` snd d)
       = Just (h:fst d, snd d)    -- We don't want multiple dots
    | otherwise = Nothing       -- Not a number, stop looking!
parseNumber(h:ls)
|isDigit h
=如果没有,则为p

然后就是([h],ls)--使用
找到的数字,其中只有d=…
是危险的:如果在
p
时访问它,整个程序将崩溃。通过这样做,您必须在代码中添加这样的检查(正如您已经正确地做的那样),并且小心不要忘记其中任何一项

还有更安全的方法,例如使用
case p of Nothing->;只需d->…
,使用
可能的
消除器,或使用functor/applicative/monad工具。让我们使用
case
来保持简单:

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

不,你不能。我们都想要它,但没有人能想出一个合理的语法

将它们放在不同的函数中

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


parseNumber :: String -> Maybe (String, String)
parseNumber [] = Just ("", "")
parseNumber (h:ls)
    | isDigit h  = f_p (h:ls)            
    | h == '.'   = temp (h: ls)         
    | otherwise  = Nothing       -- Not a number, stop looking!


f_p :: String -> Maybe (String, String)
f_p (h:ls)
    | parseNumber ls == Nothing  = Just([h], ls)         -- Digit found <<< ERROR!!
    | otherwise                  = Just (h:fst d, snd d) -- Ends in a digit
    where 
        Just d = parseNumber ls -- Float version of p. Not used if p is Nothing


temp :: String -> Maybe (String, String)
temp (h:ls)
    | parseNumber ls == Nothing  = Nothing                 -- Ends in a point
    | not ('.' `elem` (snd d))   = Just (h:(fst d), snd d) -- We don't want multiple dots
    where 
        Just d = parseNumber ls -- Float version of p. Not used if p is Nothing
isDigit::Char->Bool
isDigit c=c>='0'&&c Maybe(字符串,字符串)
parseNumber[]=仅(“,”)
密码(h:ls)
|isDigit h=f_p(h:ls)
|h=='.=temp(h:ls)
|否则=没有——不是数字,不要看了!
字符串->可能(字符串,字符串)
f_p(h:ls)

|parseNumber ls==Nothing=Just([h],ls)--找到的数字最近的GHC现在具有
多路IF

{-# 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

谢谢,它工作得很好。我只是觉得读起来有点难。这就是我想建议的方法。不过,我认为在答案正文中有一点值得注意:在这种情况下,到
dig-dot
的转换是可以的,因为
dig
dot
从互斥的防护开始,但通常它们可能不会,然后从
dig
dot
可能是不可取的。这可以通过多行if或
构造的
case()来处理,尽管在不需要时语法有点笨拙(如此处)。@DanielWagner即使守卫不是互斥的,其中一个会首先出现,因此,将其转换为
guard1 guard2
对我来说仍然是有效的。如果两个守卫不是互斥的,并且
p
失败,但
dot
成功,
dig-dot
将成功,而原版不尝试
dot
就会失败。我不相信我能理解-如果
p
失败,
dot
将无法成功。如果警卫不是相互排斥的,情况仍然如此。
{-# 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
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