我最近遇到了以下代码,这让我很困扰
lowerSafeForeignCall dflags block
| (entry, middle, CmmForeignCall { .. }) <- blockSplit block
= do
-- do block stuffs
-- Block doesn't end in a safe foreign call:
| otherwise = return block
Run Code Online (Sandbox Code Playgroud)
这段代码来自 https://phabricator.haskell.org/rGHCb0534f78a73f972e279eed4447a5687bd6a8308e
在文件editor / cmm / CmmLayoutStack.hs中
983行
我真的很想知道第二行是什么<-。我相信lowerSafeForeignCall是一个函数,并且| “ 否则 ”表示此功能使用了防护功能。所以
(entry, middle, CmmForeignCall { .. }) <- blockSplit block
Run Code Online (Sandbox Code Playgroud)
必须是布尔类型。但是<-在任何do块之外。我在网上做了一些搜索,但仍然没有关于此用法的任何线索。
最近,我试图在我的一些实际案例制作系统中使用Haskell。Haskell类型系统确实为我提供了很大的帮助。例如,当我意识到我需要某种类型的功能时
f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b
Run Code Online (Sandbox Code Playgroud)
实际上有类似的功能foldM,foldlM和foldrM。
但是,真正令我震惊的是这些功能的定义,例如:
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldr f' return xs z0
where f' x k z = f z x >>= k
Run Code Online (Sandbox Code Playgroud)
因此函数f'必须为以下类型:
f' :: a -> b …Run Code Online (Sandbox Code Playgroud) 我试图在一个简单的生产系统中采用ReaderT模式的想法。
在原始示例中,数据类型Env定义为:
data Env = Env
{ envLog :: !(String -> IO ())
, ...
}
Run Code Online (Sandbox Code Playgroud)
在我的实现中,我定义了一个类型类Serializable来帮助我记录不同的数据类型。这样我就可以拥有更通用的日志记录功能(包括不同文件格式的序列化):
data Env = Env
{ evnLog :: (Serializable a) => a -> FilePath -> IO ()
, ...
}
Run Code Online (Sandbox Code Playgroud)
当然,这是行不通的。错误消息是:
Not in scope: type variable ‘a’
|
61 | { envLog :: (Serializable a) =>
| ^
Run Code Online (Sandbox Code Playgroud)
如果a包含在的Type构造函数中Env,我将被迫不断地在ReaderT中更改Context信息,这确实很麻烦。
我只想将此通用函数传递给一系列计算,并在需要时使用它。
是否有可能不引入 aType的Type构造函数Env?也许ReaderT模式需要更多技巧来使用?
我注意到 Option<&T> 和 Option<T> 的映射函数有些奇怪,经过快速谷歌搜索后,还有其他人注意到了同样的问题,如 这个问题中所述。我将仅使用相同的示例。
let greet: Option<String> = Some("hi".to_string());
let mapped = greet.map(|e|e);
dbg!(mapped);
dbg!(greet);
Run Code Online (Sandbox Code Playgroud)
错误消息是:
use of moved value: `greet` ....
Run Code Online (Sandbox Code Playgroud)
另一方面,下面的代码是可以的。
let greet: Option<String> = Some("hi".to_string());
let mapped = greet.as_ref().map(|e|e);
dbg!(mapped);
dbg!(greet);
Run Code Online (Sandbox Code Playgroud)
地图函数的类型是:
pub const fn map<U, F>(self, f: F) -> Option<U>
Run Code Online (Sandbox Code Playgroud)
因此,调用者的所有权应该转移到映射中的“self”,该问题的解释是“Option<&T>implements Copy”。
因此,Option<T> 转移所有权从而导致错误,而 Option<&T> 只是创建一个新副本。
但是,我找不到任何显示“Option<&T> Implements Copy”的地方,更糟糕的是,来自文档:
/// The `Option` type. See [the module level documentation](self) for more.
#[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)]
#[rustc_diagnostic_item = "Option"] …Run Code Online (Sandbox Code Playgroud) 有一个清单 lc
*Main Lib MetaDefinition WHparseCSV WHparseTxT Set> :info lc
lc :: IO [Int] -- Defined at <interactive>:2:5
*Main Lib MetaDefinition WHparseCSV WHparseTxT Set> length <$> lc
1704399
Run Code Online (Sandbox Code Playgroud)
我想知道这个列表的基数,所以我尝试通过执行以下操作将此列表转换为集合:
*Main Lib MetaDefinition WHparseCSV WHparseTxT Set> import Data.Set as Set
*Main Lib MetaDefinition WHparseCSV WHparseTxT Set> let sc = Set.fromList <$> lc
Run Code Online (Sandbox Code Playgroud)
但是,当我试图计算基数时,我得到了错误:
*Main Lib MetaDefinition WHparseCSV WHparseTxT Set> length <$> sc
*** Exception: Prelude.!!: index too large
Run Code Online (Sandbox Code Playgroud)
类型sc是正确的:
*Main Lib MetaDefinition WHparseCSV WHparseTxT Set> :info sc
sc :: …Run Code Online (Sandbox Code Playgroud)