tl;博士
如果我理解正确,Haskell 没有 F# 那样的子类型。因此,我希望它没有用于匹配的类型测试模式,例如 F#。它是否有任何可用于元编程的类似结构?
案例分析
我有一个 F# project我在其中解耦了通过消息传递机制进行通信的模块。最近我一直想知道这段代码会是什么样子,或者如果我要将它移植到 Haskell 是否可以这样写。
基本思路是这样的。消息是从消息接口(interface)继承的类型:
type Message = interface end
处理程序是一个函数,它采用
Message
的特定子类型。并返回 Message
:type Handle<'TMsg when 'TMsg :> Message> = 'TMsg -> Message
有一个
Bus
与 publish
将消息分发到其内部 channel 的方法。有一个Channel<'TMsg>
每个消息类型,并且这些是在注册处理程序时动态添加的。总线将所有消息发布到所有 channel ,如果类型错误, channel 将简单地返回一个空序列:type Channel<'TIn when 'TIn :> Message>(...) = ...
interface Channel with
member x.publish (message : Message) =
match message with
| :? 'TIn as msg ->
Seq.map (fun handle -> handle msg) _handlers
|> Seq.filter (fun msg -> msg <> noMessage)
| _ -> Seq.empty
最终,我在这里所做的是动态元编程,它允许我拥有仍然通过中间相同的机器传递的强类型消息。我对 Haskell 的了解不如 F#,而且我不知道如何在 Haskell 中做到这一点。
我说 Haskell 没有
match... with... :?... as...
对吗?构造?它是否具有类似的结构或其他方法来解决此类问题?是否有某种装箱/拆箱机制?
最佳答案
Haskell 被设计成可以在运行时完全删除类型。也就是说,当实现存储类型为 T
的值时在内存中,不需要用一些标签来标记它,上面写着“这是 T
类型”。
作为返回,这提供了很好的参数保证,也称为“自由定理”。例如,具有多态类型的函数
f :: a -> a
必须返回其参数或无法终止。也就是说,我们知道
f=id
(如果我们知道它会终止)。具体来说,这意味着没有办法写出类似的东西
f :: a -> a
f x = if a == Int then x+1 else x
如果想要做这样的事情,可以通过
Data.Typeable
手动添加类型标签。类(class):{-# LANGUAGE ScopedTypeVariables, GADTs, TypeOperators #-}
import Data.Typeable
f :: forall a . Typeable a => a -> a
f x = case eqT :: Maybe (a :~: Int) of
Just Refl -> x+1
Nothing -> x
注意类型是如何改变的,现在有一个约束。它必须这样做,因为函数的效果违反了无约束多态类型的自由定理。
因此,如果您确实需要执行运行时类型检查,请携带
Typeable
约束。请注意,这可能过于笼统。如果你知道你有少量类型,也许你可以使用 sum 类型,并在构造函数上使用普通模式匹配来测试类型:data T = TInt Int
| TChar Char
f :: T -> T
f (TInt i) = TInt (i+1)
f (TChar c) = TChar c
关于Haskell 匹配构造类似于 F# 类型测试模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32343283/