如何处理 Haskell 中的“可能 [值]”列表?

Posted

技术标签:

【中文标题】如何处理 Haskell 中的“可能 [值]”列表?【英文标题】:How to deal with a list of 'Maybe [values]' in Haskell? 【发布时间】:2021-08-19 21:14:17 【问题描述】:

为了学习 Haskell,我尝试改编康拉德·巴尔斯基 (Conrad Barski) 的优秀著作《Land of Lisp》中的一些练习。我们的想法是制作一个简单的文本游戏引擎。

具体我试过了:

type Clau = String
type Descripcio = String
type Valors = [String]

-- NOTE : Ideas of types http://learnyouahaskell.com/making-our-own-types-and-typeclasses
data Lloc = Lloc String String String deriving (Show) 
llocSituacio :: Lloc -> String  
llocSituacio (Lloc situacio _ _ ) = situacio  
llocDireccio :: Lloc -> String
llocDireccio (Lloc _ direccio _) = direccio
llocPas :: Lloc -> String
llocPas ( Lloc _ _ pas) = pas

nodes :: [(Clau,Descripcio)]
nodes = [("living-room","you are in the living-room. a wizard is snoring loudly on the couch.")
           ,("garden","you are in a beautiful garden. there is a well in front of you.")
           , ("attic", "you are in the attic. there is a giant welding torch in the corner.")]

edges :: [([Char], [Lloc])]
edges = [ ("living-room", [(Lloc "garden"  "west" "door"), ( Lloc "attic" "upstairs" "ladder") ])
        , ("attic", [(Lloc "living-room"  "east"  "door")])
        , ("garden", [(Lloc "living-room" "east"  "door")])]

describePath :: Lloc -> String  
describePath  e = "There is " ++ llocPas e ++ " going " ++ llocDireccio e ++ " from here." 

起初,它似乎运作良好。例如:

*TextGame> describePath (Lloc "living-room"  "east"  "door")
"There is door going east from here."

但是当我尝试将函数应用到列表时,我得到了这个错误:

situacio = "garden"
map (describePath) (lookup situacio edges)



<interactive>:2:22: error:
    • Couldn't match expected **type ‘[Maybe Lloc]’**
                  with actual **type ‘Maybe [Lloc]’**
    • In the second argument of ‘map’, namely ‘(lookup situacio edges)’
      In the expression: map (describePath) (lookup situacio edges)
      In an equation for ‘it’:
          it = map (describePath) (lookup situacio edges)

错误很明显,但我无法解决它。我想解析 Maybe 的值列表并使用运行良好的函数 describePath 打印路径:

有什么想法吗?此外,如果有人想分享替代方案或觉得此代码可能更符合 Haskell 风格,请随时讨论。

【问题讨论】:

也许这个旧答案有帮助? ***.com/questions/3375483/… 它是map-function,而不是map。 【参考方案1】:

可能有一些更高级的库助手,但我认为您应该首先学习如何以最基本(和一般)的方式处理Maybes:使用模式匹配。

case lookup situacio edges of
   Nothing   -> [] -- not found, how do you want to handle this case?
   Just locs -> map describePath locs

通常,人们希望将结果重新包装在另一个 Maybe 中,例如:

case lookup situacio edges of
   Nothing   -> Nothing -- not found
   Just locs -> Just (map describePath locs)

在这种情况下,我们可以使用库辅助函数来缩短代码:

map describePath <$> lookup situacio edges

【讨论】:

非常感谢您的回答!它完美地工作!但是我意识到我不完全理解运算符 ,fmap 不一样吧!?它包括您指出的模式!?这就是区别?! @Mandorman f &lt;$&gt; x 恰好是 Maybe 函子的 fmap f x:它在 Just 的“下方”应用 f,并保持 Nothing 原样。【参考方案2】:

非常感谢chi,它工作得很好。我刚刚做了一个新功能:

describePaths situacio edges = case lookup situacio edges of
    Nothing -> []
    Just locs -> map describePath locs

.. 效果很好:

*TextGame> situacio = "living-room"
*TextGame> describePaths situacio edges
["There is door going west from here.","There is ladder going upstairs from here."]

但我发现我并不完全理解 运算符。我关注的是:What does <$> mean in Haskell?

所以我遵循建议:https://hoogle.haskell.org/?hoogle=%3C$%3E

这是一个 Functor:

(<$>) :: Functor f => (a->b) -> f a -> f b

其实和fmap一模一样:

fmap :: Functor f => (a -> b) -> f a -> f b

好像是一样的:

*TextGame> (*2) <$> [1..3]
[2,4,6]
*TextGame> fmap (*2) [1..3]
[2,4,6]

但是,实际上它们是不同的:

*TextGame> map describePath <$> lookup situacio edges
Just ["There is door going west from here.","There is ladder going upstairs from here."]
*TextGame> fmap (describePath) (lookup situacio edges)

<interactive>:30:22: error:
    • Couldn't match type ‘[Lloc]’ with ‘Lloc’
      Expected type: Maybe Lloc
        Actual type: Maybe [Lloc]
        ....

有人可以多说一点吗?我不完全明白为什么'fmap(describePath)(查找位置边缘)'不起作用? (我正在玩 Maybe's 和 Just's 但是......)

【讨论】:

您从上一个示例中删除了map,正确的翻译是fmap (map describePath) (lookup situacio edges)。这里的fmap 处理Maybemap 处理[Lloc] 中的列表。 哦,我明白了!我现在明白了!非常感谢!

以上是关于如何处理 Haskell 中的“可能 [值]”列表?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Haskell,我如何处理大量的 XML?

如何处理 Mongoose 中的 ENUM 值?

如何处理下拉angular-ui中的大项目列表?

如何处理 DRF 中的空索引列表?

如何处理嵌套的属性列表

python中的all()如何处理空列表