当我使用MultiParamTypeClasses时,我可以创建忽略其中一个类型参数的类函数(即下面的"身份").
{-# LANGUAGE MultiParamTypeClasses #-}
data Add = Add
data Mul = Mul
class Test a b where
identity::a
instance Test Int Add where
identity = 0
instance Test Int Mul where
identity = 1
Run Code Online (Sandbox Code Playgroud)
(这是一个精简版本,当然在完整的程序中会有其他功能使用"b").
示例编译,但我永远无法访问身份!
main = do
putStrLn (show (identity::Int))
Run Code Online (Sandbox Code Playgroud)
导致"使用'身份'时没有(Test Int b0)的实例.
有没有办法获取身份?如果没有,编译器是否应该禁止我创建一个不使用所有类型参数的类函数?
我想把Foreign.Storable分成两部分......
import Foreign
data FullData type1 type2 = FullData {first::type1, second::type2}
instance (Storable type1, Storable type2)=>Storable (FullData type1 type2) where
sizeOf _ = sizeOf (undefined::type1) + sizeOf (undefined::type2)
alignment _ = 0 --I am just setting this to zero for testing....
main = putStrLn $ show $ sizeOf (undefined::FullData Int Char)
Run Code Online (Sandbox Code Playgroud)
然而,这失败了 -
storableTest.hs:13:44:
Could not deduce (Storable a1) arising from a use of `sizeOf'
from the context (Storable type1, Storable type2)
bound by the instance declaration at storableTest.hs:12:10-74
The …Run Code Online (Sandbox Code Playgroud) 到目前为止,我已经避免了需要unsafePerformIO,但今天可能需要改变....我想看看社区是否同意,或者是否有人有更好的解决方案.
我有一个库,需要使用存储在一堆文件中的一些配置数据.这些数据保证是静态的(在运行期间),但需要在无法编译Haskell程序的最终用户编辑的文件中(极少数情况下).(细节是不重要的,但将"/etc/mime.types"视为一个相当不错的近似值.它是一个在很多程序中使用的大型几乎静态的数据文件).
如果这不是一个库,我会使用IO monad ....但是因为它是一个在我的代码中被调用的库,它实际上迫使IO monad冒出几乎所有我写的多个模块!虽然我需要一次性读取数据文件,但这种低级别调用是有效的纯粹,所以这是一个非常不可接受的结果.
仅供参考,我计划将调用包装在unsafeInterleaveIO中,以便只加载所需的文件.我的代码看起来像这样....
dataDir="<path to files>"
datafiles::[FilePath]
datafiles =
unsafePerformIO $
unsafeInterleaveIO $
map (dataDir </>)
<$> filter (not . ("." `isPrefixOf`))
<$> getDirectoryContents dataDir
fileData::[String]
fileData = unsafePerformIO $ unsafeInterleaveIO $ sequence $ readFile <$> datafiles
Run Code Online (Sandbox Code Playgroud)
鉴于读取的数据是引用透明的,我很确定unsafePerformIO是安全的(这已在很多地方讨论过,例如" 使用unsafePerformIO合适吗? ").不过,如果有更好的方法,我很乐意听到它.
最新情况:
回应Anupam的评论......
有两个原因导致我无法将lib分解为IO和非IO部分.
首先,数据量很大,我不想一次将其全部读入内存.请记住,IO总是严格读取....这就是我需要进行unsafeInterleaveIO调用以使其变得懒惰的原因.恕我直言,一旦你使用unsafeInterleaveIO,你也可以使用unsafePerformIO,因为风险已经存在.
其次,打破IO特定部分只是替代IO monad的冒泡和IO读取代码的冒泡,以及传递数据(我可能实际上选择使用状态monad传递数据无论如何,所以将IO monad替换为各州的monad并不是一个改进.如果低级函数本身不是纯粹的,那就不会那么糟糕了(想想我上面的/etc/mime.types示例,想象一下Haskell extensionToMimeType函数,它本质上是纯粹的,但需要获取数据库来自文件的数据......突然,堆栈中从低到高的所有内容都需要调用或通过a readMimeData::IO String.为什么每个人main甚至需要关心多层深度子模块的库选择?).
如果我的 .cabal 文件有多个可执行文件,我可以通过键入名称挑选出一个来构建
cabal build myExecutable
Run Code Online (Sandbox Code Playgroud)
但我很懒,只想打字
cabal build
Run Code Online (Sandbox Code Playgroud)
对于默认目标(我可以忍受为辅助可执行文件输入额外的字符)。
这可能吗?(我一直在谷歌搜索并浏览阴谋集团手册一段时间了......还没有明确的答案)。
我必须这样做,例如,每天 1000 次....
问题说明了一切....我正在使用Data.Conduit.Network,有时服务器没有启动.默认超时需要几分钟,我的程序需要在几秒钟内知道.
{-# LANGUAGE OverloadedStrings #-}
import Data.Conduit.Network
main = do --use any IP address that isn't up.... I use 1.2.3.4 for testing
runTCPClient (clientSettings 80 "1.2.3.4") $ \server -> do
putStrLn "connected"
Run Code Online (Sandbox Code Playgroud)
我在文档和来源中上下打量,答案对我来说并不清楚.我想这可能是不可能的......
回复@haoformayor答案的其他信息....
我最终使用了@haoformayor建议的类似方法,但需要进行一些更改才能使其正常工作.这是我目前的工作代码.
runTCPClientWithConnectTimeout::ClientSettings->Double->(AppData->IO ())->IO ()
runTCPClientWithConnectTimeout settings secs cont = do
race <- newChan
resultMVar <- newEmptyMVar
timerThreadID <- forkIO $ do
threadDelaySeconds secs
writeChan race False
clientThreadID <- forkIO $ do
result <-
try $
runTCPClient settings $ \appData -> do
writeChan race True …Run Code Online (Sandbox Code Playgroud) 我已经在多个地方读过列表的编写器monad将该完整列表保存在内存中,因此不应该用于除小样本之外的任何其他内容(例如,不记录日志).
但是,为了测试声明,我编写了以下程序,并且实际上表明它成功地输出了一个懒惰的无限列表!
import Control.Monad.Writer
createInfiniteList :: Int -> Writer [Int] ()
createInfiniteList i = do
tell [i]
createInfiniteList (i+1)
main :: IO ()
main = do
let x = execWriter $ createInfiniteList 1
print x
Run Code Online (Sandbox Code Playgroud)
我看过这个程序输出超过10亿个项目(它运行得非常快),并且监视我的机器上的内存使用率从未超过0.1%.
作家monad是否已被重写以修复原始问题?我可以指望它将来继续以这种方式工作吗?
注意 - 我知道存在更好的日志记录monad(我在其他地方使用它们)...我想要的用例不是日志记录(但它是类似的)
我在用
ghc-options: -Wall
Run Code Online (Sandbox Code Playgroud)
在我的.cabal文件中,并且喜欢它....
....除非我讨厌它.例如,我有一个Constants.hs看起来像这样的文件
numDogs=1000
numCats=2000
......
....etc for like 100 lines
Run Code Online (Sandbox Code Playgroud)
....当然-Wall抱怨我不提供所有类型的签名,而是将文件更改为此
numDogs::Int
numDogs=1000
numCats::Int
numCats=2000
....etc
Run Code Online (Sandbox Code Playgroud)
真的会很愚蠢.
那么,有没有办法在每个文件的基础上关闭ghc-opts.
(我知道我可以从cabal中省略ghc-options,并把它放在我想要它使用的每个文件中{-# OPTIONS_GHC -Wall #-},但是当我这样做时,我经常忘记文件,所以我宁愿不这样做办法)
ArrayRef 似乎是提供可调整大小的IO阵列的软件包,但....
ArrayRef 似乎已经过时了(它甚至不会用新的GHC编译).
有谁知道在GHC/Haskell中创建可调整大小的数组的现代方法?我最终可能会采用相关的东西(如序列),但如果可能的话,我希望坚持使用持续时间读取/修改的东西.
有没有一种干净的方法来避免以下样板:
给定一个记录数据类型定义...。
data Value = A{ name::String } | B{ name::String } | C{}
Run Code Online (Sandbox Code Playgroud)
编写安全返回的函数 name
getName :: Value -> Maybe String
getName A{ name=x } = Just x
getName B{ name=x } = Just x
getName C{} = Nothing
Run Code Online (Sandbox Code Playgroud)
我知道您可以使用Template Haskell做到这一点,我正在寻找一种比这更清洁的解决方案,也许是GHC扩展或其他我忽略的东西。
我正在从用户那里获取输入,代码如下:
putStrLn $ "Enter number"
num <- getLine
main = print $ num
Run Code Online (Sandbox Code Playgroud)
当我运行此代码时,编译器会出现以下错误:
ra.hs:10:5: parse error on input `<-'
Run Code Online (Sandbox Code Playgroud)
如何删除此错误?我试图使用空格,以及制表符,但错误仍然存在.请帮忙.