正如Typeclassopedia所证明的那样,从类别理论中引入的当前堆栈类似于历史的一个纠结事故,而不是一个美丽的连贯整体.
特别是,这使得跟踪正在发生的事情变得相当困难.
这些东西应该是什么样的,如果像向后兼容性,代码重复或易处理的短类型签名这样的小问题不是问题?
好的,所以编写器monad允许你将东西写入[通常]某种容器,并在最后收回容器.在大多数实现中,"容器"实际上可以是任何幺半群.
现在,还有一个"读者"monad.这一点,你可能会认为,将提供双操作-从某种容器,一个项目在一个时间逐步阅读.实际上,这不是通常的读者monad提供的功能.(相反,它只是提供了对半全局常量的轻松访问.)
要真正写一个单子这是双重平时作家单子,我们就需要某种结构是双重的独异.
我以为会有这个问题,但我找不到一个.
我希望我的程序打印出它编译的日期.设置它的最简单方法是什么?
我可以想到几种可能性,但它们都不是你所谓的"简单".理想情况下,我希望每次运行时ghc --make Foo都可以Foo打印出编译日期.
想到的各种不容易的可能性:
学习模板Haskell.弄清楚如何使用Data.Time来获取今天的日期.找到一种如何将其转换为字符串的方法.(现在我的程序需要TH才能工作.我还需要说服它每次重新编译该模块,否则我得到该模块的编译日期[永不改变]而不是整个程序.)
编写一个shell脚本,生成一个包含系统日期的小Haskell模块.(现在我必须使用那个shell脚本而不是直接编译我的程序.而且,Windows上的shell脚本还有很多不足之处!)
坐下来写一些Haskell代码,生成一个包含日期的小Haskell模块.(比以前的想法更便携 - 但仍需要额外的构建步骤或打印日期不正确.)
可能有一些方法可以通过Cabal来做到这一点 - 但我真的想要打包这个小程序只是为了获得日期工具吗?
有没有人有更简单的建议?
我正在Haskell中编写一个终端模式程序.我如何阅读原始按键信息?
特别是,似乎有一些东西在Haskell之上提供行编辑工具.如果我这样做getLine,我似乎能够使用向上箭头来获取前一行,编辑文本,并且只有当我按Enter键时,文本才会对Haskell应用程序本身可见.
我所追求的是能够阅读单个按键,因此我可以自己实现行编辑.
也许我的问题不清楚.基本上我想构建类似Vi或Emacs(或Yi)的东西.我已经知道有终端绑定可以让我进行花哨的控制台模式打印,所以输出端不应该是一个问题.我只是想找到一种获取原始按键输入的方法,所以我可以做一些事情,比如(例如)当用户按下字母K时将K添加到当前文本行,或者当用户将文件保存到磁盘时按Ctrl + S.
定义像这样的运算符非常容易
(@) :: [x -> y] -> [x] -> [y]
Run Code Online (Sandbox Code Playgroud)
它获取函数列表和输入列表,并返回输出列表.有两种明显的方法可以实现这一点:
要么定义也同样微不足道.关于它的好处是你现在可以做类似的事情
foo :: X -> Y -> Z -> R
bar :: [X] -> [Y] -> [Z] -> [R]
bar xs ys zs = [foo] @@ xs @@ ys @@ zs
Run Code Online (Sandbox Code Playgroud)
这概括为任意数量的函数参数.
到现在为止还挺好.现在针对问题:如何更改类型签名以@@使类型签名bar变为
bar :: [X] -> [Y] -> [Z] -> [[[R]]]
Run Code Online (Sandbox Code Playgroud)
实现这种类型的函数并不难; 其中任何一个都会这样做:
bar xs ys zs = map (\ x -> map (\ y -> map (\ z -> foo x …Run Code Online (Sandbox Code Playgroud) 今天,我发现自己键入以下代码:
case () of
_ | x < 15 -> ...
_ | x < 25 -> ...
_ | x < 50 -> ...
_ -> ...
Run Code Online (Sandbox Code Playgroud)
这个意思很直接,但只是感觉...... 说错了case ().有没有人有更好的建议?
我想,因为我在品牌上x,我本来可以写的case x.但这仍然让我没有任何实际的模式匹配; 这都是关于守卫的.这仍然感觉很奇怪.
如果我按Ctrl + C,这会引发异常(总是在线程0?).如果你愿意,你可以抓住这个 - 或者,更有可能的是,运行一些清理,然后重新抛出它.但通常的结果是以某种方式停止程序.
现在假设我使用Unix kill命令.据我了解,kill基本上将(可配置的)Unix信号发送到指定的进程.
Haskell RTS如何响应这一点?它在某处记录了吗?我会想象,在发送SIGTERM会有如按Ctrl + C相同的效果,但我不知道那是事实...
(当然,你可以使用kill发送与杀戮毫无关系的信号.再一次,我会想象 RTS会忽略,比方说,SIGHUP或者SIGPWR,但我不确定.)
我意识到我可能会后悔在我的余生中询问这个问题,但是......有没有办法将XSLT应用于XML文件,而 XML文件没有明确引用XSLT文件?
就个人而言,我觉得整个点 XSLT的是,你可以将几个不同的转换到同一个原始的XML文件,从它产生多种不同的结果.但是,如果必须在源XML文件中指定转换,那么这确实不起作用.似乎要改变转换,你必须改变底层的原始数据文件,这似乎是错误的......
那么有没有办法创建某种文件,说"采用这种XML和这种XSLT并在浏览器窗口中呈现结果"?
编辑:
也许我的问题不清楚.
如果我打开记事本,编写XML文件,并在其中提及XSLT文件的名称,那么当我双击XML文件时,Web浏览器将应用指定的XSLT.有没有什么方法可以说服浏览器在不改变原始XML文件的情况下执行此操作?或者我将被迫搜索命令行XSLT处理器?
我有一个小的测试框架.它执行一个循环,执行以下操作:
生成一个小的Haskell源文件.
执行此操作runhaskell.该程序生成各种磁盘文件.
处理刚刚生成的磁盘文件.
这种情况发生了几十次.事实证明,这runhaskell占用了程序执行时间的绝大部分.
一方面,runhaskell设法从磁盘加载文件,标记它,解析它,进行依赖性分析,从磁盘加载20KB更多文本,标记并解析所有这些,执行完整类型推断,检查类型,desugar到Core的事实,链接编译的机器代码,并在解释器中执行该事情,所有在2秒的时间内,当你想到它时实际上非常令人印象深刻.另一方面,我仍然希望让它变得更快.;-)
编译测试器(运行上述循环的程序)产生了微小的性能差异.编译脚本链接的20KB库代码产生了相当明显的改进.但是每次调用它仍然需要大约1秒钟runhaskell.
生成的Haskell文件每个只有1KB以上,但实际上只有一部分文件发生了变化.也许编译文件并使用GHC的-e开关会更快?
或者,也许是重复创建和销毁许多操作系统进程的开销,这会减慢这种速度?每次调用都runhaskell可能导致操作系统探索系统搜索路径,找到必要的二进制文件,将其加载到内存中(当然这已经在磁盘缓存中?),将其链接到任何DLL,并将其激活.有没有什么方法可以(轻松地)保持一个GHC运行实例,而不是不断创建和销毁操作系统进程?
最终,我想总有GHC API.但正如我所理解的那样,这种噩梦难以使用,高度无证,并且在GHC的每个小点发布时都容易发生根本变化.我正在尝试执行的任务非常简单,所以我并不想让事情变得更加复杂.
建议?
更新:切换到GHC -e(即,现在编译除正在执行的一个表达式之外的所有内容)没有产生可测量的性能差异.在这一点上似乎很清楚,它是所有操作系统开销.我想知道我是否可以创建一个从测试仪到GHCi的管道,从而只使用一个操作系统进程......
在Haskell中处理真正大型二进制文件的最有效方法是什么?
标准答案是将整个文件作为惰性ByteString读取,然后使用Binary数据包之类的东西来编写解析器.这有几个问题......
首先,像Binary这样的库并没有真正处理解析失败,我明显地希望解析有时会失败.
其次,我没有解析整个文件内容.我将跳过它的大块.并且从磁盘读取数十亿字节的数据只是为了让垃圾收集器再次将其丢弃似乎相当不可靠.
与此相关,我需要能够判断我想要执行的跳过是否会将我从文件的末尾带走(如果出现错误则会出错).
我可能还需要向后搜索,或者可能需要查找文件中的特定字节偏移量,这似乎不是懒惰的ByteString方法所支持的.(最终将整个文件保存在RAM中存在严重危险.)
当然,另一种方法是逐个读取单个字节,与hSeek命令交错.但现在的问题是,一次读取一个字节的文件效率如何?听起来它也可能很慢.我不确定是否会hSetBuffering对此产生影响.(?)
然后当然有mmap.但是,如果在大文件上使用虚拟内存系统,那似乎就会吓坏.(这很奇怪,考虑到它存在的全部目的......)
伙计们,我们怎么想?在I/O性能和代码可维护性方面,最好的方法是什么?