Haskell DSL的异构列表

Haskell DSL的异构列表,haskell,types,dsl,existential-type,gadt,Haskell,Types,Dsl,Existential Type,Gadt,TL;DR 它们是我构造一个约束到某个typeclass的异构列表的一种方式,而不需要对每个元素调用构造函数吗 我终于有机会深入研究Haskell,我正在尝试构建一个DSL,为类似SQL的语言生成查询字符串。下面是我试图尝试的伪代码,一旦我更好地了解了如何实现这一点,这些类型将得到进一步改进。请原谅我含糊不清 我的dsl所需的语法如下 from :: String -> Query select :: [String] -> Query -> Query select ["t

TL;DR

它们是我构造一个约束到某个typeclass的异构列表的一种方式,而不需要对每个元素调用构造函数吗


我终于有机会深入研究Haskell,我正在尝试构建一个DSL,为类似SQL的语言生成查询字符串。下面是我试图尝试的伪代码,一旦我更好地了解了如何实现这一点,这些类型将得到进一步改进。请原谅我含糊不清

我的dsl所需的语法如下

from :: String -> Query
select :: [String] -> Query -> Query
select ["this", "that"] $ from "tbl"
SELECT 
    this + that as stuff, 
    this
FROM tbl;
问题是,我还想在参数中允许选择诸如列算术和逻辑运算符之类的内容。比如说

(<~) :: String -> Column -> Column -- used for assigning a new name
add  :: String -> String -> Column

select ["stuff" <~ "this" `add` "that", "this"] $ from "tbl"
显而易见的问题是,这需要一个异构列表。我可以创建一个新的数据类型来封装这些值并继续我的生活,但我认为结果要麻烦得多

select ["stuff" <~ (Column "this") `add` (Column "that"), Column "this", Column "that"] $ from "tbl"

select[“stuff”不,在Haskell中不可能有合适的异构列表。您始终需要某种构造函数。但是,可能还有另一种解决方案。您可以重新定义组合符以返回
String
s而不是
Column
s。可能是这样的

infixl 5 `add`
add :: String -> String -> String
add a b = a ++ " + " ++ b

infix 2 <~ 
(<~) :: String -> String -> String
new <~ old = old ++ " as " ++ new
infixl 5`add`
添加::字符串->字符串->字符串
添加一个b=a++“++”b
中缀2字符串

新的不,在Haskell中不可能有合适的异构列表。您将始终需要某种构造函数。但是,可能还有另一种解决方案。您可以重新定义组合符以返回
String
s,而不是
Column
s。可能是这样的

infixl 5 `add`
add :: String -> String -> String
add a b = a ++ " + " ++ b

infix 2 <~ 
(<~) :: String -> String -> String
new <~ old = old ++ " as " ++ new
infixl 5`add`
添加::字符串->字符串->字符串
添加一个b=a++“++”b
中缀2字符串

新的GHC有一个类似于下面这种情况的扩展:
OverloadedStrings
。OverloadedStrings背后的基本思想是字符串文字可以是实现
Data.string.IsString
typeclass的任何类型。因此,对于您的代码,您可以这样做

import Data.String

newtype Column = Column String

instance IsString Column where
  fromString = Column
然后按原样定义组合符。现在,所需的裸字符串文本将被解释为

Main*> :t ["those" <~ "this" `and` "that", "thing"]
["those" <~ "this" `and` "that", "thing"] :: [Column]

Main*>:t[“那些”GHC有一个类似于这样的扩展:
OverloadedStrings
。OverloadedStrings背后的基本思想是字符串文本可以是实现
Data.string.IsString
typeclass的任何类型。因此,对于您的代码,您可以这样做

import Data.String

newtype Column = Column String

instance IsString Column where
  fromString = Column
然后按原样定义组合符。现在,所需的裸字符串文本将被解释为

Main*> :t ["those" <~ "this" `and` "that", "thing"]
["those" <~ "this" `and` "that", "thing"] :: [Column]

Main*>:t[“那些”我想在某个时候包括类型保证查询不会生成奇怪的东西。例如,我不想允许像
select[“this”,sum“that”]$这样的操作从“tbl”
中选择一个值和一个向量,而我允许
select[“this”`add`(sum“that”)]$from“tbl”
我想在某些时候包括类型保证,以确保查询不会生成奇怪的东西。例如,我不想允许像
select[“this”,sum“that”]$from“tbl”
这样的操作,因为这是选择单个值和向量,而我允许
select[“this”`add`(sum“that”)]$from“tbl”
不是这样的,但是您可以使用Template Haskell来定制一些语法。警告:不适合胆小的人。或者,您可以使用一些技巧使异构列表更易于编写(HList
包有这样一个功能)。这看起来很漂亮,但您的错误消息会很可怕。不是这样,但您可以使用Template Haskell来创建一些自定义语法。警告:不适合胆小的人。或者,您可以使用类来使用一些技巧,以使异构列表更易于编写(HList
包有这样一个功能)。这看起来很漂亮,但您的错误消息会很可怕。这似乎正是我所需要的。这似乎正是我所需要的