gpt4 book ai didi

haskell - 如何构建用于从 Haskell 中的记录中查找字段的 DSL

转载 作者:行者123 更新时间:2023-12-03 14:57:45 25 4
gpt4 key购买 nike

TL;DR: 我需要帮助弄清楚如何生成代码,这些代码将从不同记录的各个字段中返回少数数据类型(可能只是 Double 和 Bool)中的一种。

长格式:假设以下数据类型

data Circle = Circle { radius :: Integer, origin :: Point }
data Square = Square { side :: Integer }

和一些样板代码
circle = Circle 3 (Point 0 0)
square = Square 5

我正在构建一个小型 DSL,并希望用户编写如下内容
circle.origin
square.side

它会生成类似于
origin . circle
side . square

例如,在解析这个时,我会使用字符串“circle”和“origin”。我现在需要将它们转换为函数调用。我显然可以有这样的东西:
data Expr a = IntegerE (a -> Integer)
| PointE (a -> Point)

lookupF2I "side" = Just $ IntegerE side
lookupF2I "radius" = Just $ IntegerE radius
lookupF2I _ = Nothing

lookupF2P "origin" = Just $ PointE origin
lookupF2P _ = Nothing

每个返回的数据类型都有一个查找函数。从 DSL 的角度来看,每种数据类型拥有一个函数是实用的,因为它只会真正处理 2 或 3 种数据类型。然而,这似乎不是一种特别有效的做事方式。有没有更好的方法(肯定)这样做?如果没有,有没有一种方法可以从我希望能够从中查找字段的各种记录中生成各种查找函数的代码?

其次,还有解析出的 "circle"的问题。或 "square"需要调用相应的 circlesquare功能。如果我要使用类型类来实现它,我可以执行以下操作:
instance Lookup Circle where
lookupF2I "radius" = Just $ IntegerE radius
lookupF2I _ = Nothing
lookupF2P "origin" = Just $ PointE origin
lookupF2P _ = Nothing

但是这让我不得不弄清楚在查找函数上强制执行哪种类型,更糟糕的是必须为我想要使用它的每个(许多)记录手动编写实例。

注意: Circle 的事实和 Square可以使用单个 ADT 表示对我的问题来说是偶然的,因为这是一个人为的例子。实际的代码将包含各种非常不同的记录,它们唯一的共同点是具有相同类型的字段。

最佳答案

我尝试使用 Template Haskell 来提供一种很好且类型安全的方法来解决这个问题。为此,我从给定的字符串构造了表达式。

我想 Lens 包可以做到这一点,但它可能是一个更简单、更灵活的解决方案。

它可以这样使用:

import THRecSyntax
circleOrigin = compDSL "circle.origin.x"

并且是这样定义的:

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH

compDSL :: String -> Q Exp
compDSL s = return
$ foldr1 AppE
$ map (VarE . mkName)
(reverse $ splitEvery '.' s)

所以结果表达式为: x (origin circle)
注: splitEvery是将列表拆分为取出给定元素的子列表的函数。示例实现:

splitEvery :: Eq a => a -> [a] -> [[a]]
splitEvery elem s = splitter (s,[])
where splitter (rest, res) = case elemIndex elem rest of
Just dotInd -> let (fst,rest') = splitAt dotInd rest
in splitter (tail rest', fst : res)
Nothing -> reverse (rest : res)

这是使用给定语法创建嵌入式 DSL 的重量级但类型安全的方法。

关于haskell - 如何构建用于从 Haskell 中的记录中查找字段的 DSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13199681/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com