Haskell 匹配构造类似于 F# 类型测试模式?

标签 haskell types casting f# pattern-matching

tl;博士

如果我理解正确,Haskell 没有 F# 那样的子类型。因此,我希望它没有用于匹配的类型测试模式,例如 F#。它是否有任何可用于元编程的类似结构?

案例分析

我有一个 F# project我在其中解耦了通过消息传递机制进行通信的模块。最近我一直想知道这段代码会是什么样子,或者如果我要将它移植到 Haskell 是否可以这样写。

基本思路是这样的。消息是从消息接口(interface)继承的类型:

type Message = interface end

处理程序是一个函数,它采用 Message 的特定子类型。并返回 Message :

type Handle<'TMsg when 'TMsg :> Message> = 'TMsg -> Message

有一个Buspublish将消息分发到其内部 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/

相关文章:

haskell - 用户管理一键完成

haskell - 在 Haskell 中将 (CurlCode, String) 更改为 String

python - 结合 maybe 和 seq monads : confused at the output

检查一种整数类型的值是否适合另一种整数类型

C++ 等价于代数数据类型?

Haskell 单子(monad) IO

c++ - 在头文件中引用 ADT

arrays - 如何在 Delphi 中将数组转换为指针并返回?

C++ - 如何正确地将 double 转换为 int

c++ - 向上转换不透明指针