以下代码创建数组,初始化,然后返回不可变数组。
import Data.Array
import Control.Monad.ST
import Data.Array.ST
import qualified Data.Array.IArray as IA
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s (STArray s Int Int)
-- some mutation writeArray arr 0 1 etc
iarr <- freeze arr -- :: ST s (IA.IArray Array s)
return iarr
iarr <- freeze arr
导致类型错误
> No instance for (IA.IArray b0 Int) arising from a use of `freeze'
> The type variable `b0' is ambiguous
我已经尝试过注释掉了类型签名和其他变种,到目前为止没有运气。请在思考过程中包含如何解决问题的思考过程。
答案 0 :(得分:3)
问题是您没有为createCustomInitializedArray
提供签名。由于Monomorphism Restriction Haskell将尝试推断createCustomInitializedArray
的具体类型。但它不能,因为freeze
在结果中是多态的。
有四种方法可以解决这个问题:
createCustomInitializedArray
提供单形类型签名。例如:ST s (Array Int Int)
使用如下具体类型注释iarr
:
return (iarr :: Array Int Int)
为createCustomInitilizedArray
提供多态类型签名。
{-# LANGUAGE FlexibleContexts #-}
...
createCustomInitializedArray :: IA.IArray a Int => ST s (a Int Int)
...
NoMonomorphismRestriction
语言扩展,让Haskell推断出多态类型。我认为这是最不利的选择,因为您应该为所有顶级功能提供类型签名。答案 1 :(得分:3)
您的功能具有以下最常见的类型:
createCustomeInitializedArray :: IA.IArray a Int => ST s (a Int Int)
其中包含类型类约束IA.IArray a Int
。实际上这有点棘手,因为它将第二个参数中的类型数组部分应用于固定类型。 Haskell98不允许这样做;如果您启用-XFlexibleContexts
扩展程序,GHC会执行此操作。除此之外,这显然是一个多态类型,但由于createCustomeInitializedArray
没有(显式)参数,编译器希望通过constant applicative form将其设为dreaded monomorphism restriction。即它拒绝推断多态类型,您需要使用显式签名来请求它。无论如何,使用顶级签名是一个非常好的主意,所以这样做:
{-# LANGUAGE FlexibleContexts #-}
createCustomeInitializedArray :: IA.IArray a Int => ST s (a Int Int)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s (STArray s Int Int)
-- ...
iarr <- freeze arr
return iarr
我补充一点,你对newArray (0,10) 0
的本地签名并不像它看起来那样:Haskell类型变量没有作用域,所以s
那里对边远州的s
一无所知;以下内容更忠实于编译器所看到的内容:
createCustomeInitializedArray :: IA.IArray a Int => ST s (a Int Int)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s₁ (STArray s₁ Int Int)
-- ...
因此它使本地操作完全独立于外部的s
,然后将其实例化为该状态参数。嗯,这在这个特定的例子中实际上没有问题,但通常它可能是一个令人讨厌的问题(特别是,外部s
的约束不会传播到内部的{-# LANGUAGE FlexibleContexts, ScopedTypeVariables, UnicodeSyntax #-}
createCustomeInitializedArray :: ∀ s a . IA.IArray a Int => ST s (a Int Int)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s (STArray s Int Int)
-- ...
iarr <- freeze arr
return iarr
。因此,这是我推荐的代码:
arr :: STArray s Int Int <- newArray (0,10) 0
这也可以简洁地写成
ping
答案 2 :(得分:0)
只是提醒一下。使用矢量对我来说似乎更容易,需要的知识也更少。
using (var client = new ImapClient ()) {
// Note: depending on your server, you might need to connect
// on port 993 using SecureSocketOptions.SslOnConnect
client.Connect ("imap.server.com", 143, SecureSocketOptions.StartTls);
// Note: use your real username/password here...
client.Authenticate ("username", "password");
// open the Inbox folder...
client.Inbox.Open (FolderAccess.ReadOnly);
// search the folder for new messages (aka recently
// delivered messages that have not been read yet)
var uids = client.Inbox.Search (SearchQuery.New);
Console.WriteLine ("You have {0} new message(s).", uids.Count);
// ...but maybe you mean unread messages? if so, use this query
uids = client.Inbox.Search (SearchQuery.NotSeen);
Console.WriteLine ("You have {0} unread message(s).", uids.Count);
client.Disconnect (true);
}
答案 3 :(得分:0)
您可以使用freezeSTArray
中的GHC.Arr
而不是freeze
来指定模糊类型:
import Data.Array
import Control.Monad.ST
import Data.Array.ST
import qualified Data.Array.IArray as IA
import GHC.Arr(freezeSTArray)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s (STArray s Int Int)
-- ...
freezeSTArray arr