键入俄罗斯方块 - 卡住混合 monadic 和纯代码

type tetris - stuck mixing monadic and pure code

我正在尝试在 haskell 中实现 vulkan 教程的点点滴滴。

现在我一直在尝试从 c:

翻译这段代码
for (const char* layerName : validationLayers) {
    bool layerFound = false;

    for (const auto& layerProperties : availableLayers) {
        if (strcmp(layerName, layerProperties.layerName) == 0) {
            layerFound = true;
            break;
        }
    }

    if (!layerFound) {
        return false;
    }
}

return true; 

到此为止:

-- This has type (Int -> Text) -> Bool
let partOne = all (`elem` requiredValidationLayers) . flip map [0 .. realCount-1]
-- This has type Int -> IO Text
let partTwo i = do
        let layerProperty = advancePtr layerProperties i
        myField_ <- readStringField @"layerName" layerProperty
        pure $ toS myField_ :: IO Text

我觉得我拥有所有的部分,但我也可能会走完全错误的方向。

如何将这些东西放在一起?

谢谢

PS:好的,我刚刚注意到集合包含检查可能被逆转了——没关系,为了这个问题,让我们假装它实际上没问题

感谢所有评论者,我想我现在明白了:)

这是它的样子(在 IO ()do 块内):

supportedLayers <- for [0 .. realCount-1] $ \i -> do
    let layerProperty = advancePtr layerProperties i
    myField_ <- readStringField @"layerName" layerProperty
    pure $ toS myField_ :: IO Text
return $ requiredValidationLayers `includes` supportedLayers

哪里

includes :: Eq a => [a] -> [a] -> Bool
includes a b = all (`elem` b) a

我将从一些假设开始:

  1. 你有一个类型data Layer = ...
  2. 你有类型别名type Name = String
  3. 你有一些功能layerName :: Layer -> Name

我将介绍纯函数的定义,不是因为它非常重要,而是因为它使用了一种从纯代码转移到不纯(即 IO 依赖)代码的技术。


给定的图层是否有给定的名称?

首先,你有基础操作

strcmp(layerName, layerProperties.layerName) == 0

这是一个简单的 Haskell 函数,如果图层具有给定的名称,它采用 NameLayer 以及 returns True

hasName :: Name -> Layer -> Bool
hasName name layer = name == layerName layer

几层中的一层是否有几个名称中的任何一个?

但是我们没有一个名称或图层;我们有每个列表。我们可以通过使用列表的 Applicative 实例来模拟不确定性来轻松处理这个问题。

import Control.Applicative

foo :: [Name] -> [Layer] -> [Bool]
foo = liftA2 hasName

我不会为这个函数起个好名字,因为我们不需要。

现在,我们可以获得every name 与every 层比较的结果列表,但我们不关心个别结果:我们只需要 one 值来说明我们是否找到匹配项。为此,我们将使用 or :: [Bool] -> Bool.

findMatch :: [Name] -> [Layer] -> Bool
findMatch names layers = or (foo names layers)

foo 很简单,我们只需内联它的定义,这样我们就不需要想出一个更好的名字:

findMatch :: [Name] -> [Layer] -> Bool
findMatch names layers = or (liftA2 hasName names layers)

处理 IO

现在,我们一直假设我们已经将名称和图层列表作为纯值。但如果我们不这样做呢?如果我们只从文件或其他地方读取列表,那么我们有 IO [Name] and/or IO [Layer] 怎么办?解决方案是再次使用 liftA2,但我们将使用 IO 实例而不是 Applicative 的列表实例。

ionames :: IO [Name]
ionames = ...

iolayers :: IO [Layer]
iolayers = ...

result :: IO Bool
result = liftA2 findMatch ionames iolayers