我正在编写一个函数,可以在一系列任意符号中进行搜索.我想使它足够通用,以便它可以在列表,Foldable
s以及ByteString
s和Text
s上运行.将其概括Foldable
为简单.但是如何包含ByteString
s和Text
s?当然我可以转换ByteString
成一个列表,然后调用我的功能,但我会失去所有的优势ByteString
.
举一个具体的例子,假设我们想要制作直方图函数:
import Control.Monad.State
import qualified Data.Foldable as F
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Word
import qualified Data.ByteString as B
import qualified Data.Text as T
type Histogram a = Map a Int
empty :: (Ord a) => Histogram a
empty = Map.empty
histogramStep :: (Ord a) => a -> Histogram a -> Histogram a
histogramStep k = Map.insertWith (+) k …
Run Code Online (Sandbox Code Playgroud) 是否可以在运行时生成并运行TemplateHaskell生成的代码?
在运行时使用C,我可以:
与模板Haskell类似的事情是否可能?
我最近在使用threepenny-gui时遇到了一个错误
,它通过将符号中的模式匹配的代码更改为<-
与let符号的模式匹配来解决.
在这两种模式匹配形式之间进行转换时,我是否应该期望改变行为?
具体如下代码:
在IO monad中:
Just events <- Map.lookup elid <$> readMVar sElementEvents
Run Code Online (Sandbox Code Playgroud)
改为:
mevents <- Map.lookup elid <$> readMVar sElementEvents
let Just events = mevents
Run Code Online (Sandbox Code Playgroud)
这是一个提交的链接,为我解决了问题:https: //github.com/Davorak/threepenny-gui/commit/fbf6cbe25875fafdc64f7a111ddebf485b45143b
其他平台细节:os:10.8.5 ghc:7.6.3
编辑:添加了这个发生在IO monad的事实
正如在最近的一篇文章中所指出的那样,范围内的模块不能按预期工作.
该线程的一个例子是:
Module[{expr},
expr = 2 z;
f[z_] = expr;
f[7]]
(*2 z*)
Run Code Online (Sandbox Code Playgroud)
但以下工作几乎与预期一致.
Module[{expr},
expr = 2 z;
Set@@{f[z_], expr};
f[7]]
(*14*)
Run Code Online (Sandbox Code Playgroud)
什么语言设计考虑使wolfram选择此功能?
编辑:请参阅Jefromi的第一条评论我将z从局部变量更改为not并忘记更改输出.它不会影响问题.
编辑2:Michael Pilat的观点似乎是Block和Module具有不同的功能.我想我理解他的观点,但我认为这与我的问题是正交的.所以这是一个更新.
我可以在笔记本中的全局级别使用以下代码:
expr = 2 z;
f[z_] = expr;
f[7]
(*output: 14*)
Run Code Online (Sandbox Code Playgroud)
但是当我将相同的代码块放入模块并使expr本地时,它会产生不同的输出.
Clear[f];
Module[{expr},
expr = 2 z;
f[z_] = expr;
f[7]]
(*output: 2z*)
Run Code Online (Sandbox Code Playgroud)
如果跟踪上面的模块调用,则会发现Set [f [z_],expr]被重写为Set [f [z $ _,expr].现在这个z-> z $转换发生在Set的lhs和rhs上.然而,它在expr被评估之前发生,这导致在全局级别获得不同的结果.
只有当rhs具有Module调用的本地符号时,才会发生转换z-> z $.
为什么Mathematica选择在模块调用中更改此语法?做出这个决定的是什么语言/实现设计权衡.
我有以下代码使用GHC API加载模块并获取表达式的类型:
typeObjects :: [String] -> [String] -> IO [Type]
typeObjects modules objects = do
defaultErrorHandler defaultDynFlags $ do
runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
targets <- mapM ((flip guessTarget) Nothing) modules
setTargets targets
result <- load LoadAllTargets
case result of
Failed -> error "Compilation failed"
Succeeded -> do
m <- mapM (((flip findModule) Nothing) . mkModuleName) modules
setContext m []
values <- mapM exprType objects
return values
Run Code Online (Sandbox Code Playgroud)
如果表达式没有进行类型检查,则整个程序崩溃:
TestDynamicLoad: panic! (the 'impossible' happened)
(GHC version …
Run Code Online (Sandbox Code Playgroud) 有时需要执行一些复杂的例程来检索或保存正在处理的数据.在这种情况下,人们想要分离数据生成和数据处理逻辑.常见的方法是使用类似iteratee的功能.有很多不错的图书馆:管道,管道等.在大多数情况下,他们会做这件事.但是AFAIK它们(除了,可能是管道)受到处理顺序的限制.
但考虑一个日志查看器示例:人类可能希望随机来回漫步.他也可以放大和缩小.我担心迭代者在这里无能为力.
一个简单的解决方案可能如下所示:
-- True is for 'right', 'up', etc. and vice versa
type Direction = Bool
class Frame (f :: * -> *) where
type Dimension f :: *
type Origin f :: * -> *
grow', shrink' move' :: Monad m => Dimension f -> Direction -> f a -> m (f a)
move' dim dir f = grow' dim dir f >>= shrink' dim (not dir)
liftF' :: (Origin f a -> b) -> f a -> …
Run Code Online (Sandbox Code Playgroud) 我经常发现以下类型的增量定义很有用:
(define (foo) (display "bar"))
(foo)
;prints bar
(define foo (let ((bar foo))
(lambda ()
(display "foo")
(bar))))
(foo)
;prints foobar
Run Code Online (Sandbox Code Playgroud)
如何使用宏预先形成此类增量定义?我无法让let-syntax提供相同的功能.
目前我使用plt方案,但也希望在不同的lisp实现中看到答案.
编辑:
天真的我想做以下事情:
(define-syntax foo
(syntax-rules ()
((_) (display "bar"))))
(define-syntax foo
(let-syntax ((old-foo (syntax-rules () ((_) (foo)))))
(syntax-rules ()
((_) (begin
(display "foo")
(old-foo))))))
Run Code Online (Sandbox Code Playgroud)
将朴素宏翻译为工作plt方案宏:
(require-for-syntax scheme/base)
(define-syntax foo
(syntax-rules ()
[(foo) (display "bar")]))
(define-syntax foo
(let ([old (syntax-local-value #'foo)])
(lambda (stx)
#`(begin #,((syntax-rules ()
[(_) (begin (display "foo"))]) stx)
#,(old #'(_))))))
(foo)
Run Code Online (Sandbox Code Playgroud)
如果我错过了一个更好的方法让我知道.
我正在尝试使用Haskell中的pipes-attoparsec解析二进制数据.管道(代理)涉及的原因是将读取与解析交错以避免大文件的高内存使用.许多二进制格式基于块(或块),它们的大小通常由文件中的字段描述.我不确定这个块的解析器是什么被调用,但这就是我所说的标题中的"sub-parser".我遇到的问题是以简洁的方式实现它们而没有可能很大的内存占用.我想出了两个在某些方面都失败的替代方案.
备选方案1是将块读入单独的字节串并为其启动单独的解析器.简洁,大块将导致高内存使用.
备选方案2是在相同的上下文中保持解析并跟踪消耗的字节数.这种跟踪容易出错,并且似乎会影响组成最终blockParser的所有解析器.对于格式错误的输入文件,在比较跟踪大小之前,还可以通过进一步解析比大小字段所指示的方式来浪费时间.
import Control.Proxy.Attoparsec
import Control.Proxy.Trans.Either
import Data.Attoparsec as P
import Data.Attoparsec.Binary
import qualified Data.ByteString as BS
parser = do
size <- fromIntegral <$> anyWord32le
-- alternative 1 (ignore the Either for simplicity):
Right result <- parseOnly blockParser <$> P.take size
return result
-- alternative 2
(result, trackedSize) <- blockparser
when (size /= trackedSize) $ fail "size mismatch"
return result
blockParser = undefined
main = withBinaryFile "bin" ReadMode go where
go h = fmap print . runProxy . runEitherK …
Run Code Online (Sandbox Code Playgroud) 使用管道库,我想编写一个程序来从某个源读取数据并单独累积它(比如说Sum
).最简单的方法是,
import Control.Proxy as
import Data.Monoid (Sum)
main = do
let source = enumFromToS (0::Int) 5
a <- runWriterT $ runProxy $ source >-> foldD Sum
print a
Run Code Online (Sandbox Code Playgroud)
当然,虽然这适用于小型源,但由于WriterT
累加器的惰性,大输入会导致可怕的堆栈溢出.
值得庆幸的是,它似乎pipes
预料到了这一点,提供了一个WriterP
带有严格累加器的代理.不幸的是,围绕这个代理的文档非常稀少.经过一番探索(并简化问题而不是为每个下游元素累积1),我来到这个程序,
import Control.Proxy
import Control.Proxy.Trans.Writer
import Data.Monoid (Sum)
main = do
let source = enumFromToS (0::Int) 5
a <- runProxy $ runWriterK $ source >-> \x->tell (Sum 1::Sum Int)
print a
Run Code Online (Sandbox Code Playgroud)
当然,这个程序甚至没有正确地执行简化的任务,因为它累积到1而不是6.如果我没有弄错,这个行为可以解释为管道在终止之前只读取一个元素.要重复直到输入结束,我想出了以下内容,
import Control.Proxy
import Control.Proxy.Trans.Writer
import Data.Monoid (Sum)
main = do
let …
Run Code Online (Sandbox Code Playgroud) 例如,有......
consumer :: Proxy p => () -> Consumer p a (EitherT String IO) ()
producer :: Proxy p => () -> Producer p a (EitherT ByteString IO) r
Run Code Online (Sandbox Code Playgroud)
......我该如何工作?
session :: EitherT ByteString (EitherT String IO) ()
session = runProxy $ producer >-> consumer
Run Code Online (Sandbox Code Playgroud)
注:我读过混合基地单子在Control.Proxy.Tutorial
.我得到了第一个例子,但无法理解人为的例子.更多的例子,不是那么明显但不那么做作,可能会澄清如何使用hoist
和lift
匹配任何基础monad的组合.
haskell ×8
ghc-api ×2
attoparsec ×1
bytestring ×1
c ×1
do-notation ×1
fold ×1
lenses ×1
lisp ×1
macros ×1
parsing ×1
proxies ×1
runtime ×1
scheme ×1
text ×1
typechecking ×1