键入俄罗斯方块 - 卡住混合 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
我将从一些假设开始:
- 你有一个类型
data Layer = ...
- 你有类型别名
type Name = String
- 你有一些功能
layerName :: Layer -> Name
我将介绍纯函数的定义,不是因为它非常重要,而是因为它使用了一种从纯代码转移到不纯(即 IO
依赖)代码的技术。
给定的图层是否有给定的名称?
首先,你有基础操作
strcmp(layerName, layerProperties.layerName) == 0
这是一个简单的 Haskell 函数,如果图层具有给定的名称,它采用 Name
和 Layer
以及 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
我正在尝试在 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
我将从一些假设开始:
- 你有一个类型
data Layer = ...
- 你有类型别名
type Name = String
- 你有一些功能
layerName :: Layer -> Name
我将介绍纯函数的定义,不是因为它非常重要,而是因为它使用了一种从纯代码转移到不纯(即 IO
依赖)代码的技术。
给定的图层是否有给定的名称?
首先,你有基础操作
strcmp(layerName, layerProperties.layerName) == 0
这是一个简单的 Haskell 函数,如果图层具有给定的名称,它采用 Name
和 Layer
以及 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