是否可以使用您自己的数据类型来模拟函数?
是否可以使用您自己的数据类型和某些 GHC 扩展来模拟函数?我想做的是例如
(想象的语法)
data MyFunc = MyFunc String (Int->Int)
instance (Int->Int) MyFunc where
($) (MyFunc _ f) i = f i
inc = MyFunc "increment" (1+)
test = inc 1
,即携带一些元信息并且可以进行模式匹配的数据,但仍然可以像常规函数一样调用。现在,我知道我可以定义自己的中缀运算符,例如 $$
并调用 inc $$ 1
,但是能够使用常规函数调用语法将非常有用在嵌入式 DSL 中。
Is it possible to emulate a function with your own data type with some GHC extension? What I want to do is e.g.
(imaginary syntax)
data MyFunc = MyFunc String (Int->Int)
instance (Int->Int) MyFunc where
($) (MyFunc _ f) i = f i
inc = MyFunc "increment" (1+)
test = inc 1
I.e. data that carries some meta-information with it and can be pattern matched, but which can still be called like a regular function. Now, I know that I could define my own infix operator like $$
and call inc $$ 1
, but being able to use the regular function call syntax would be very useful in embedded DSLs.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,可以在有限的范围内做到这一点。
但首先我们需要
定义
我要为您的名字添加更多结构,以便获得更好的显示支持。 ;)
然后让我们定义一个类:
现在,考虑类型:
magic
的结果类型是(a -> b)
或 aM a b< /代码>。
因此它可以用作
MyFunc
的成员。现在,这种类型有些不令人满意,因为您无法在其上分派实例,但这确实意味着工作得很好。
我们甚至可以用一种相当不错的方式来展示它们。尽管我们不能在
MyFunc
上使用 show,但我们可以为M
定义它。然后我们可以创建一个可以应用于
M a b
(以及扩展为任何MyFunc
)的函数来获取M a b
。我们可以定义一个特殊的组合器来显示
MyFunc
s:然后我们就可以玩了。我们可以定义
MyFunc
的组合。而且因为我给了名称足够的结构,我们甚至可以为更复杂的组合得到正确的括号,而没有不必要的括号。
但请记住,您将无法为
MyFunc
定义任何实例,因为它只能是type
,而不能是newtype
。为了定义实例,您必须在M
上定义它们,然后使用m
转换为该类型,以便隐式调度有一个可以获取的类型。由于等级 2 类型,如果您在本地上下文中大量使用这些,您可能还需要打开
NoMonoLocalBinds
和/或NoMonomorphismRestriction
。Yes, it can be done to a limited extent.
But first we'll need
Let's define
I'm adding more structure to your names so I can get nicer show support. ;)
Then lets define a class:
Now, consider the type:
The result type of
magic
is either(a -> b)
or aM a b
.So it can be used as a member of
MyFunc
. Now, this type is somewhat unsatisfying, because you can't make instances dispatch on it, but it does mean thatworks just fine.
We can even make a rather nice way to show them. Even though we can't use show on
MyFunc
, we can define it forM
.Then we can make a function we can apply to
M a b
(and by extension anyMyFunc
) to get out anM a b
.and we can define a special combinator to show
MyFunc
s:Then we can play. We can define compositions of
MyFunc
s.And because I gave enough structure to the names, we even get correct parenthesization for more complicated compositions, without needless parentheses.
But remember, you won't be able to define any instances for
MyFunc
, since it can only be atype
, and not anewtype
. In order to define instances you'll have to define them onM
, and then usem
to convert to that type so that implicit dispatch has a type to grab onto.Because of the rank 2 type, if you use these heavily in local contexts, you may also want to turn on
NoMonoLocalBinds
and/orNoMonomorphismRestriction
.不可以,语法
f e
不能重载。f
必须具有类型S -> T。
但是,如果您进行深度嵌入,您仍然可以使用 EDSL 做很多事情,即让您的函数构建语法树而不是计算。
No, the syntax
f e
cannot be overloaded. Thef
has to have typeS -> T
.But you can still do a lot with EDSLs if you do a deep embedding, i.e., you let your functions build syntax trees instead of computing.
您不能直接重载函数调用语法,不。
您可以制作自己的自定义箭头类型 --- 请参阅Control.Arrow.然后,您可以使用箭头符号 (您需要在源文件顶部包含
{-# LANGUAGE Arrows #-}
)。这对您来说是否足够好取决于您的 DSL 的需求。You can't directly overload function call syntax, no.
You can make your own custom arrow type --- see Control.Arrow. You can then invoke your "functions" using arrow notation (you will need to include
{-# LANGUAGE Arrows #-}
at the top of your source file). Whether this is good enough for you depends on the needs of your DSL.