- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用 scotty 和 acid state 编写了一个 Web 应用程序,现在我想使用类型类来为我的应用程序的测试功能提供替代实现。我了解了它的一般概念,并且能够将它应用到如此简单的示例中,但由于我使用的是酸性状态,因此涉及到很多类型类和模板 haskell,我还不太适应。
所以我有这些针对不同功能的直接类
class Logging m where
log :: T.Text -> m ()
class Server m where
body :: m B.ByteString
respond :: T.Text -> m ()
setHeader :: T.Text -> T.Text -> m ()
class Db m where
dbQuery :: (MethodState event ~ Database,QueryEvent event) => event -> m (EventResult event)
dbUpdate :: (MethodState event ~ Database,UpdateEvent event) => event -> m (EventResult event)
而且我还为我的“生产”monad 提供了它们的实例。
但是当涉及到数据库功能时,我无法按照自己的意愿工作。
类看起来是这样的
class Db m where
dbQuery :: (MethodState event ~ Database,QueryEvent event) => event -> m (EventResult event)
dbUpdate :: (MethodState event ~ Database,UpdateEvent event) => event -> m (EventResult event)
生产 monad 的实例工作正常,因为它只将事件传递给 acid state 的更新和查询函数,但对于测试 monad,我希望有这样的东西: 实例 Db 测试位置 dbQuery (GetVersion) = 使用 (testDb.clientVersion) dbQuery (GetUser name) = preuse (testDb.users.ix name) dbUpdate(PutUser name user) = users %= M.insert name user ...这样我就可以匹配 GetVersion、GetUser 等(由模板 haskell 函数 makeAcidic ... 生成)并指定在测试环境中应如何处理它们。
但是我得到了错误:
Could not deduce: event ~ GetVersion
from the context: (MethodState event ~ Database, QueryEvent event)
bound by the type signature for:
dbQuery :: (MethodState event ~ Database, QueryEvent event) =>
event -> Test (EventResult event)
at Main.hs:88:3-9
‘event’ is a rigid type variable bound by
the type signature for:
dbQuery :: forall event.
(MethodState event ~ Database, QueryEvent event) =>
event -> Test (EventResult event)
at Main.hs:88:3
• In the pattern: GetVersion
In an equation for ‘dbQuery’:
dbQuery (GetVersion) = use (testDb . clientVersion)
In the instance declaration for ‘Db Test’
• Relevant bindings include
dbQuery :: event -> Test (EventResult event)
(bound at Main.hs:88:3)
我想那是因为 GetVersion、GetUser 等都有自己不同的类型。那么有没有办法做到这一点?
我尝试了 Peter Amidon 提出的建议,但遗憾的是它仍然没有编译这里是我的测试代码
{-# LANGUAGE GADTs #-} -- For type equality
{-# LANGUAGE TypeOperators #-} -- For type equality
{-# LANGUAGE TypeFamilies #-} -- For EventResult
{-# LANGUAGE ScopedTypeVariables #-} -- For writing castWithWitness
{-# LANGUAGE TypeApplications #-} -- For convenience
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
import Control.Lens
import Data.Acid
import qualified Data.Text.Lazy as T
import Types
import Data.Typeable
main = return ()
getUser :: Username -> Query Database (Maybe User)
getUser name = preview (users . ix name)
getVersion :: Query Database T.Text
getVersion = view clientVersion
$(makeAcidic ''Database ['getUser,'getVersion])
castWithWitness :: forall b a. (Typeable a, Typeable b)
=> a -> Maybe (b :~: a, b)
castWithWitness x = case eqT @a @b of
Nothing -> Nothing
Just Refl -> Just (Refl, x)
exampleFunction :: forall a. QueryEvent a => a -> EventResult a
exampleFunction (castWithWitness @GetVersion -> (Just Refl, Just GetVersion)) = "1.0"
exampleFunction (castWithWitness @GetUser -> (Just Refl, Just (GetUser n))) = Nothing
这里是错误
Main.hs:124:49: error:
• Couldn't match expected type ‘Maybe
(GetVersion :~: a, GetVersion)’
with actual type ‘(Maybe (t1 :~: t2), t0)’
• In the pattern: (Just Refl, Just GetVersion)
In the pattern:
castWithWitness @GetVersion -> (Just Refl, Just GetVersion)
In an equation for ‘exampleFunction’:
exampleFunction
(castWithWitness @GetVersion -> (Just Refl, Just GetVersion))
= "1.0"
• Relevant bindings include
exampleFunction :: a -> EventResult a (bound at Main.hs:124:1)
Main.hs:124:61: error:
• Couldn't match expected type ‘t0’
with actual type ‘Maybe GetVersion’
‘t0’ is untouchable
inside the constraints: t2 ~ t1
bound by a pattern with constructor:
Refl :: forall k (a :: k). a :~: a,
in an equation for ‘exampleFunction’
at Main.hs:124:55-58
• In the pattern: Just GetVersion
In the pattern: (Just Refl, Just GetVersion)
In the pattern:
castWithWitness @GetVersion -> (Just Refl, Just GetVersion)
Main.hs:125:46: error:
• Couldn't match expected type ‘Maybe (GetUser :~: a, GetUser)’
with actual type ‘(Maybe (t4 :~: t5), t3)’
• In the pattern: (Just Refl, Just (GetUser n))
In the pattern:
castWithWitness @GetUser -> (Just Refl, Just (GetUser n))
In an equation for ‘exampleFunction’:
exampleFunction
(castWithWitness @GetUser -> (Just Refl, Just (GetUser n)))
= Nothing
• Relevant bindings include
exampleFunction :: a -> EventResult a (bound at Main.hs:124:1)
Main.hs:125:79: error:
• Could not deduce: MethodResult a ~ Maybe a0
from the context: t5 ~ t4
bound by a pattern with constructor:
Refl :: forall k (a :: k). a :~: a,
in an equation for ‘exampleFunction’
at Main.hs:125:52-55
Expected type: EventResult a
Actual type: Maybe a0
The type variable ‘a0’ is ambiguous
• In the expression: Nothing
In an equation for ‘exampleFunction’:
exampleFunction
(castWithWitness @GetUser -> (Just Refl, Just (GetUser n)))
= Nothing
• Relevant bindings include
exampleFunction :: a -> EventResult a (bound at Main.hs:124:1)
最佳答案
在这种情况下,你想要的应该是可能的,因为一个QueryEvent
或UpdateEvent
是一个Method
,而一个Method
是 Typeable
。 Typeable
让我们可以使用 Data.Typeable
中的函数来检查我们在运行时拥有的特定类型,这是我们通常无法做到的。
这是一个独立的小例子,它不直接使用 acid-state
但开始说明这个想法:
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE PatternSynonyms #-}
这些不是绝对必要的,但可以为 Event
上的匹配创建更好的语法。
import Data.Typeable
我们需要此模块中的函数来访问运行时输入信息。
data GetVersion = GetVersion
data GetUser = GetUser String
class Typeable a => QueryEvent a where
instance QueryEvent GetVersion where
instance QueryEvent GetUser where
一组简化的类型/类来模拟 acid-state
应该产生的结果。
pattern IsEvent p <- (cast -> Just p)
这个“模式同义词”使得我们可以在模式匹配的 LHS 上编写 IsEvent p
并使其工作方式与编写 (cast ->只是 p)
。后者是一个“ View 模式”,它本质上是在输入上运行函数 cast
,然后将其与 Just p
进行模式匹配。 cast
是 Data.Typeable
中定义的函数: cast::forall a b。 (Typeable a, Typeable b) => a -> Maybe b
。这意味着,如果我们编写,例如,(cast -> Just GetVersion)
,cast
会尝试将参数转换为 类型的值GetVersion
,然后与值级 GetVersion
符号进行模式匹配;如果转换失败(暗示事件是其他事件),cast
返回 Nothing
,因此此模式不匹配。这让我们写:
exampleFunction :: QueryEvent a => a -> String
exampleFunction (IsEvent GetVersion) = "get version"
exampleFunction (IsEvent (GetUser a)) = "get user " ++ a
这就可以了:
λ> exampleFunction GetVersion
"get version"
λ> exampleFunction (GetUser "foo")
"get user foo"
您的情况有点复杂,因为函数的 RHS(类型)取决于输入的类型。为此,我们需要更多扩展:
{-# LANGUAGE GADTs #-} -- For type equality
{-# LANGUAGE TypeOperators #-} -- For type equality
{-# LANGUAGE TypeFamilies #-} -- For EventResult
{-# LANGUAGE ScopedTypeVariables #-} -- For writing castWithWitness
{-# LANGUAGE TypeApplications #-} -- For convenience
我们还可以将 EventResult
添加到我们的虚拟简单 QueryEvent
中:
class Typeable a => QueryEvent a where
type EventResult a
instance QueryEvent GetVersion where
type EventResult GetVersion = Int
instance QueryEvent GetUser where
type EventResult GetUser = String
我们可以使用
代替cast
castWithWitness :: forall b a. (Typeable a, Typeable b)
=> a -> Maybe (b :~: a, b)
castWithWitness x = case eqT @a @b of
Nothing -> Nothing
Just Refl -> Just (Refl, x)
@a
和 @b
使用 TypeApplications
将 eqT
应用于 的类型castWithWitness
应用于,它们通过 ScopedTypeVariables
使用类型签名中的 forall
绑定(bind)。 castWithWitness
类似于cast
,但除了“casted”变量外,它还返回一个证明,证明传入的类型相同。不幸的是,这使得它使用起来有点困难:不能使用 IsEvent
模式同义词,需要直接传入相关类型:
exampleFunction :: forall a. QueryEvent a => a -> EventResult a
exampleFunction (castWithWitness @GetVersion -> Just (Refl, GetVersion)) = 1
exampleFunction (castWithWitness @GetUser -> Just (Refl, GetUser n)) = n
这是有效的,因为在每种情况下,在 Refl
上匹配后,GHC 知道函数的 RHS 上的 a
是什么,并且可以减少 EventResult
类型族。
关于haskell - 使用类型类为使用 Acid-State 时提供替代实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53926860/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!