如何使用单例库中的toSing?

时间:2019-07-08 06:30:52

标签: haskell singleton dependent-type data-kinds

关于singleton库,我是一个新手,并且可能所遭受的损失超过了我在这里可以咀嚼的范围。

我已经成功地使用fromSing将“单个类型”转换为“值级术语”(我的术语正确吗?)但是,我无法理解如何使用{{ 1}}和从概念上讲如何将在运行时的值转换为类型?

这是toSing的文档所说的,我不太了解...

toSing

-- Convert an unrefined type to an existentially-quantified singleton type. toSing :: Demote k -> SomeSing k 是这样的:

SomeSing

这是否意味着从概念上讲-- An existentially-quantified singleton. This type is useful -- when you want a singleton type, but there is no way of knowing, -- at compile-time, what the type index will be. To make use of this -- type, you will generally have to use a pattern-match: foo :: Bool -> ... foo b = case toSing b of SomeSing sb -> {- fancy dependently-typed code with sb -} 基本上是在做以下事情:

fromSing

那是到目前为止,Haskell可以期望的最好结果吗?也就是说,我们需要对运行时值进行模式匹配,运行可以具有不同类型的函数,但最终它们应该统一为一个类型?

1 个答案:

答案 0 :(得分:3)

如果您编译代码:

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

module SingletonExample where
import Data.Singletons.TH
singletons [d| data Value = Value1 | Value2 |]

带有标志-ddump-splices -dsuppress-uniques,您可以看到singletons库通过模板Haskell生成的实际代码。特别是,生成的SingKind实例是:

instance SingKind Value where
  type Demote Value = Value
  fromSing SValue1 = Value1
  fromSing SValue2 = Value2
  toSing Value1 = SomeSing SValue1
  toSing Value2 = SomeSing SValue2

因此,fromSingtoSing只是从(运行时)值到(运行时)单例再返回的样板转换函数。

也就是说,fromSingtoSing不在值和类型之间转换,它们在值和单例之间转换。当您编写的函数需要单例时,通常会使用toSing

g :: SValue value -> String
g SValue1 = "one"
g SValue2 = "two"

,但您拥有的只是一个关联值。在这种情况下,您可以使用有点尴尬的构造:

f :: Value -> String
f v = case toSing v of SomeSing sv -> g sv

以必要的单例呼叫g

事实证明,对于单例的通常使用情况,只有少数情况可以起作用和/或有帮助。结果,实际上很少见到toSing用于单例代码。并且特别是,在处理与运行时相关的类型时,使用toSing既没有必要,也常常没有特别有用。

最终,如果您想学习/理解singletons库,则需要了解何时以及为什么单例有用(以及它们是类型的运行时表示形式的复杂而微妙的意义),而不是如何在它们及其关联值之间来回转换。为此,我建议阅读Hasochism论文Dependently Typed Programming with Singletons,搜索“ haskell中的依赖类型编程”和“ haskell单例”,并阅读您看到的每篇博客文章。 Weirich也有一些YouTube videos值得一试。