Haskell 有可能在哈斯克尔安顿警卫吗?
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
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