如何在没有缩进树的情况下处理嵌套的case语句?

Chr*_*ski 3 haskell functional-programming

我偶尔遇到一个小问题,我有一组嵌套的case语句,这会很麻烦.是否有任何技术/模式可用于可能有一个函数列表(这将等同于示例的case ...语句),评估所有这些,并选择匹配模式的第一个(例如:) Right x

我将它们放在列表中的具体问题是它们不一定是同一类型(我认为是单态性限制).例如以下内容:

  let possibleTags = [
          parse (parseFileReference) "file reference" xStr
        , parse (parseGitDiffReference) "git diff tag" xStr
        ]
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

• Couldn't match type ‘GitDiffReference’ with ‘FileReference’
  Expected type: Either ParseError FileReference
    Actual type: Either ParseError GitDiffReference
• In the expression:
    parse (parseGitDiffReference) "git diff tag" xStr
  In the expression:
    [parse (parseFileReference) "file reference" xStr,
     parse (parseGitDiffReference) "git diff tag" xStr]
  In an equation for ‘possibleTags’:
      possibleTags
        = [parse (parseFileReference) "file reference" xStr,
           parse (parseGitDiffReference) "git diff tag" xStr]
Run Code Online (Sandbox Code Playgroud)
abc :: Int -> String
abc = undefined

abc2 :: Int -> Float
abc2 = undefined

abc3 :: Int -> Int
abc3 = undefined

example :: Int -> Maybe String
example x = case abc x of 
  ("yes") -> Just "abc"
  ("no")  -> case abc2 x of
               1.0 -> Just "abc2"
               2.0 -> case abc3 x of
                        100 -> Just "abc3"
                        200 -> Nothing
Run Code Online (Sandbox Code Playgroud)

我理想地寻找类似下面的东西(不是有效的代码):

-- Psuedo code
example :: Int -> Maybe String
example = 
 if (abc x && "yes") then Just "abc"
 if (abc2 x && 1.0) then Just "abc2"
 if (abc3 x && 100) then Just "abc3"
Run Code Online (Sandbox Code Playgroud)

使用if条件的问题是我不能(据我所知)进行模式匹配,例如if (Just x).

chi*_*chi 6

翻译确切示例(保持非穷举模式匹配):

import Data.Foldable


example2 :: Int -> Maybe String
example2 x = asum tests
   where
   tests =
      [ case abc x of 
         "yes" -> Just "abc"
         "no"  -> Nothing
      , case abc2 x of
         1.0 -> Just "abc2"
         2.0 -> Nothing
      , case abc3 x of
         100 -> Just "abc3"
         200 -> Nothing
      ]
Run Code Online (Sandbox Code Playgroud)


lef*_*out 5

至少当结果为 时Maybe,这看起来像是该实例的一个明确的用例Alternative

example x = ("abc" <$ guard (abc x=="yes"))
         <|>("abc2" <$ guard (abc2 x==1))
         <|>("abc3" <$ guard (abc3 x==100))
Run Code Online (Sandbox Code Playgroud)