我最近一直在玩隐形眼镜,发现它们对它们的预期用途非常满意--深入研究复杂的数据结构。但是,我最喜欢它们的领域之一是数据库访问(特别是sqlite,但我认为我的问题概括到了大多数DB),但是我看不出有任何方法可以编写不会严重牺牲性能或粒度的镜头。
如果我写一个透镜(或者我认为可能是棱镜,根据NULLable字段?)从一个数据库到一个表,从一个表到一个行,从一个行到一个列,其中的每一个步骤都会产生一个数据库访问,这意味着一个访问应该是至少4。
另一方面,如果我的目标是用镜头/棱镜来映射DB 1:1,那么我就可以做很多事情--当我只想看看表中的列是什么的时候,所有不能分解成小块的镜片都是如此。
使用带有DB的镜头有意义吗?如果是这样的话,我是否错过了避免重复工作以避免不必要的DB访问的明显方法?
发布于 2014-06-28 01:28:44
我觉得你想用一种类似于linq IQueryable在c#中使用镜头的方式。
如果你有这些类型的话:
data Project = Project {
_projectId :: Int
, _projectPriority :: Int
, _projectName :: String
, _projectTasks :: [Task]
} deriving (Show)
data Task = Task {
_taskId :: Int
, _taskName :: String
, _taskEstimate :: Int
} deriving (Show)
makeLenses ''Project
makeLenses ''Task和一个数据库:
create table projects ( id, name, priority);
create table tasks (id, name, estimate, projectId);
insert into projects values (1, 'proj', 1), (2, 'another proj', 2);
insert into tasks values (1, 'task1', 30, 1), (2, 'another', 40, 1),
(3, 'task3', 20, 2), (4, 'more', 80, 2);如果您想从优先级大于1的项目中获得任务名称的列表,最好可以使用:
highPriorityTasks :: IO [String]
highPriorityTasks = db ^.. projects . filtered (\p -> p ^. projectPriority > 1 )
. projectTasks . traverse . taskName并让该数据库使用该查询:
select t.name from projects as p
inner join tasks as t on t.projectId = p.id
where p.priority > 1;不幸的是,这在库中是不可能的。基本上,为了提高数据库的效率,您(通常)必须在一个查询中完成所有操作。这样做是不可接受的:
select * from projects where priority > 1;
for each project:
select name from tasks where projectId = <project>.id 不幸的是,不可能分解函数来知道是什么建立了它们。除了类型之外,如果不运行函数,就无法找到任何关于函数的信息。因此,无法从filtered函数中提取数据以帮助构建查询。也不可能从完整的表达中提取出副镜头。所以这是不可能使用镜头库。
目前,您可以获得的最好方法是使用一组函数查询数据库,并使用透镜查询结果数据。有关这方面的示例,请参阅此关于yesod的博客文章。
一个相关的问题是,这是否有可能。为此,我们需要为数字和字符串运算符以及跟踪所做工作的组合创建一个子语言。这可能是可能的。例如,您可以构建一个Num类型,它记录对它所做的一切:
data TrackedNum = TrackedNum :-: TrackedNum
| TrackedNum :+: TrackedNum
| TrackedNum :*: TrackedNum
| Abs TrackedNum
| Signum TrackedNum
| Value Integer
deriving (Show)
instance Num TrackedNum where
a + b = a :+: b
a * b = a :*: b
a - b = a :-: b
abs a = Abs a
signum a = Signum a
fromInteger = Value
t :: TrackedNum
t = 3 + 4 * 2 - abs (-34)
> t
(Value 3 :+: (Value 4 :*: Value 2)) :-: Abs (Value 0 :-: Value 34)重复布尔运算符(为此需要一个新的类型类)、列表运算符和函数组合(即类别类)的过程,您应该能够创建一个“白盒”函数,然后可以用来创建一个高效的sql查询。不过,这可不是件小事!
https://stackoverflow.com/questions/24462070
复制相似问题