假设我正在定义一个Haskell函数f(纯函数或动作),并且在f I函数g中调用函数g.例如:
f = ...
g someParms
...
Run Code Online (Sandbox Code Playgroud)
如何用模拟版本替换函数g进行单元测试?
如果我在Java中工作,g将是SomeServiceImpl实现接口的类的方法SomeService.然后,我使用依赖注入告诉f要么使用SomeServiceImpl或MockSomeServiceImpl.我不知道如何在Haskell中做到这一点.
是介绍类型SomeService的最佳方法:
class SomeService a where
g :: a -> typeOfSomeParms -> gReturnType
data SomeServiceImpl = SomeServiceImpl
data MockSomeServiceImpl = MockSomeServiceImpl
instance SomeService SomeServiceImpl where
g _ someParms = ... -- real implementation of g
instance SomeService MockSomeServiceImpl where
g _ someParms = ... -- mock implementation of g
Run Code Online (Sandbox Code Playgroud)
然后,重新定义f如下:
f someService ... = ...
g someService someParms
...
Run Code Online (Sandbox Code Playgroud)
看起来这样可行,但我只是在学习Haskell并想知道这是否是最好的方法呢?更一般地说,我喜欢依赖注入的想法,不仅仅是为了模拟,而且还使代码更具可定制性和可重用性.通常,我喜欢不被锁定到一段代码使用的任何服务的单个实现中的想法.在代码中广泛使用上述技巧以获得依赖注入的好处是否被认为是一个好主意?
编辑:
让我们更进一步.假设我在一个模块中有一系列函数a,b,c,d,e和f,它们都需要能够从不同的模块引用函数g,h,i和j.并且假设我想能够模拟函数g,h,i和j.我可以清楚地将4个函数作为参数传递给af,但是将4个参数添加到所有函数中会有点痛苦.另外,如果我需要更改任何af的实现以调用另一种方法,我需要更改其签名,这可能会产生令人讨厌的重构练习.
使这种情况变得容易的任何技巧?例如,在Java中,我可以使用其所有外部服务构造一个对象.构造函数会将服务存储在成员变量中.然后,任何方法都可以通过成员变量访问这些服务.因此,随着方法被添加到服务中,方法签名都不会改变.如果需要新服务,则只会更改构造函数方法签名.
我正在构建一个使用MongoDB作为后端的Rails应用程序,使用MongoMapper作为ORM工具.假设在版本1中,我定义了以下模型:
class SomeModel
include MongoMapper::Document
key :some_key, String
end
Run Code Online (Sandbox Code Playgroud)
稍后在版本2中,我意识到我需要在模型上使用新的必需键.因此,在版本2中,SomeModel现在看起来像这样:
class SomeModel
include MongoMapper::Document
key :some_key, String
key :some_new_key, String, :required => true
end
Run Code Online (Sandbox Code Playgroud)
如何迁移所有现有数据以包含some_new_key?假设我知道如何为所有现有文档设置合理的默认值.更进一步,假设在版本3中,我意识到我根本不需要some_key.所以,现在模型看起来像这样
class SomeModel
include MongoMapper::Document
key :some_new_key, String, :required => true
end
Run Code Online (Sandbox Code Playgroud)
但是我的数据库中的所有现有记录都为some_key设置了值,而这只是浪费空间.我该如何收回那个空间?
使用ActiveRecord,我刚刚创建了迁移来添加some_new_key的初始值(在version1 - > version2迁移中)并删除some_key的值(在version2 - > version3迁移中).
使用MongoDB/MongoMapper执行此操作的适当方法是什么?在我看来,仍然需要一些跟踪哪些迁移的方法.这样的事情存在吗?
编辑:我认为人们忽略了我的问题.有时您希望能够在数据库上运行脚本来更改或重构其中的数据.我在上面给出了两个示例,一个是添加了新的必需密钥,另一个是可以删除密钥并且可以回收空间的示例.如何管理运行这些脚本?ActiveRecord迁移为您提供了一种简单的方法来运行这些脚本并确定已运行的脚本以及尚未运行的脚本.我显然可以编写一个Mongo脚本来对数据库进行任何更新,但我正在寻找的是一个像迁移这样的框架,可以跟踪哪些升级脚本已经运行过.
我正在尝试使用在Apache中运行的PHP通过IMAP连接到Gmail.这是在Ubuntu 9.04系统上.我有一些PHP配置问题,这使得它无法正常工作.首先,这是我为PHP设置IMAP所做的工作:
sudo apt-get install libc-client2007b libc-client2007b-dev
sudo apt-get install php5-imap
sudo /etc/init.d/apache2 start
Run Code Online (Sandbox Code Playgroud)
当我运行phpinfo()时,我得到以下imap值:
IMAP c-Client Version: 2004
SSL Support: enabled
Kerberos Support: enabled
Run Code Online (Sandbox Code Playgroud)
这是我的示例代码:
<?php
$connect_to = '{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX';
$user = 'my gmail address';
$password = 'my gmail password';
$connection = imap_open($connect_to, $user, $password)
or die("Can't connect to '$connect_to': " . imap_last_error());
imap_close($connection);
?>
Run Code Online (Sandbox Code Playgroud)
当我执行此代码时,我得到以下输出:
Warning: imap_open() [function.imap-open]: Couldn't open stream {imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX in /var/www/clint/gmail/gmail.php on line 10
Can't connect to '{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX': TLS/SSL failure for imap.gmail.com: SSL context failed
Run Code Online (Sandbox Code Playgroud)
请注意,我可以从这台计算机telnet到imap.gmail.com:993.我还可以通过IMAP将Evolution(邮件阅读器)连接到Gmail并毫无问题地获取邮件.所以,我认为这不是防火墙问题.我很确定我在PHP中没有正确设置. …
假设我有以下内容:
class Shape a where
draw a :: a -> IO ()
data Rectangle = Rectangle Int Int
instance Shape Rectangle where
draw (Rectangle length width) = ...
data Circle = Circle Int Int
instance Shape Circle where
draw (Circle center radius) = ...
Run Code Online (Sandbox Code Playgroud)
有没有办法让我定义一个形状列表,遍历列表,并在每个形状上调用绘图函数?以下代码将无法编译,因为列表元素的类型不同:
shapes = [(Circle 5 10), (Circle 20, 30), (Rectangle 10 15)]
Run Code Online (Sandbox Code Playgroud)
我知道我正在以OO的方式思考并尝试将其应用于Haskell,这可能不是最好的方法.对于需要处理不同类型对象集合的程序,最好的Haskell方法是什么?
假设我有两种数据类型Foo和Bar.Foo有字段x和y.条形图有字段x和z.我希望能够编写一个函数,它将Foo或Bar作为参数,提取x值,对其执行一些计算,然后返回一个新的Foo或Bar,并相应地设置x值.
这是一种方法:
class HasX a where
getX :: a -> Int
setX :: a -> Int -> a
data Foo = Foo Int Int deriving Show
instance HasX Foo where
getX (Foo x _) = x
setX (Foo _ y) val = Foo val y
getY (Foo _ z) = z
setY (Foo x _) val = Foo x val
data Bar = Bar Int Int deriving Show
instance HasX Bar where
getX (Bar x _) = x
setX (Bar …Run Code Online (Sandbox Code Playgroud) 我正在寻找一个允许Haskell程序与Cassandra交互的通用模块.该模块需要保持自己的状态.例如,它将具有连接池和保存新记录时要调用的回调列表.我应该如何构造代码以使该模块能够保持其状态?以下是我一直在考虑的一些方法.我是在正确的轨道上吗?(我是Haskell的新手,仍然在学习功能上最佳的思考方式.)
选项1:
该模块在(StateT的IO)monad中运行,其中s是使用Cassandra模块的整个程序的全局状态.当然,由于Cassandra模块可以被多个程序使用,因此对于Cassandra模块来说,s中的内容的细节应该是不可见的.该模块必须导出一个类型类,允许它从s中提取CassandraState并将新的CassandraState推回到s中.然后,使用该模块的任何程序都必须使其主状态成为此类型类的成员.
选项2:
该模块在(StateT CassandraState IO)monad中运行.每当有人在模块中调用一个动作时,他们就必须从隐藏它的任何地方提取CassandraState,用runState调用动作,然后取出结果状态并再次将其存放(无论在哪里).
选项3:
不要将Cassandra模块的函数放在StateT monad中.相反,让调用者在需要时显式传入CassandraState.选项2的问题在于并非模块中的所有功能都将修改状态.例如,获取连接将修改状态,并要求调用者存储结果状态.但是,保存新记录需要读取状态(以获取回调),但不需要更改状态.选项2不会给调用者任何提示连接更改状态而创建没有.
但是,如果我不再使用StateT monad并且只使用将状态作为参数的函数并返回简单值或简单值和新状态的元组,那么当状态需要保存时,调用者真的很明显.(在我的模块的封面下,我将传入状态并将它们构建到(StateT CassandraState IO)monad中,但是这个细节会被调用者隐藏.所以,对于调用者来说,接口是非常明确的,但在封面下,它只是选项2.)
选项4:
别的什么?
在构建可重用模块时,必须经常出现此问题.有什么标准的解决方法吗?
(顺便说一句,如果有人知道从Haskell与Cassandra进行交互比使用Thrift更好的方式,请告诉我!也许我根本不需要写这个.:-)
我工作的公司销售在Tomcat,WebSphere或WebLogic上运行的J2EE应用程序.我们有一个客户试图在Tomcat和WebSphere之间做出决定.他们倾向于WebSphere,因为他们担心Tomcat会有更多安全漏洞.
在网上搜索之后,从安全的角度来看,我一直无法找到任何比较主要J2EE应用服务器的健壮性的站点或研究.
你们有没有人能指出我比较应用程序服务器安全漏洞的信息?