【问题标题】:How to count the length of a tuple in Haskell?如何计算 Haskell 中元组的长度?
【发布时间】:2017-06-07 05:36:32
【问题描述】:

我尝试在 web 和 stackexchange 中搜索,但令人惊讶的是,没有人问如何在 Haskell 中以下面的形式计算元组的长度。

假设您在 Haskell 中有 (1,2,3,4) 或 (1,3,5,6,7) 之类的元组,并希望编写计算元组长度的长度函数。我怎样才能做到这一点?对于列表,我知道如何在不显式调用内置函数的情况下使用递归来做到这一点。但是元组不同,我不能用“头”-“尾”区分。

该方法是否涉及创建新的数据类型?

【问题讨论】:

  • 这样的函数的类型是什么?
  • 这就是问这个问题的重点。我无法理解这将如何成为可能。不同长度的元组不会共享相同的类型,我不知道如何利用创建新的数据类型来支持长度函数。
  • 出于好奇,您为什么要这样做?元组的长度在编译时是固定的,所以不需要“计算”任何东西。您可以使用 class TupLen a where tupLen :: a -> Int 之类的类型类和 instance TupLen (a, b) where tupLen _ = 2 等,但这不是很有用。

标签: haskell


【解决方案1】:

你没有找到任何东西的原因是计算元组的长度没有多大意义:

  • 它是预先确定的编译时间(即您也可以对其进行硬编码)
  • 您无法对这些信息做太多事情:与例如一个列表,不可能在通用元组中索引特定条目。

也就是说,可以实现您的目标,但这不应该是一个普通函数,而是一个类型级函数,也就是类型族。使用singleton 输入nats:

{-# LANGUAGE TypeFamilies, DataKinds #-}
import Data.Singletons
import Data.Singletons.TypeLits

type family TupLength a :: Nat where
  TupLength () = 0
  TupLength (a,b) = 2
  TupLength (a,b,c) = 3
  TupLength (a,b,c,d) = 4
  -- ...
  TupLength x = 1

然后

> mapM_ print [ natVal (sing :: SNat (TupLength ()))
              , natVal (sing :: SNat (TupLength (Int,String,Double)))
              , natVal (sing :: SNat (TupLength Bool)) ]
0
3
1

【讨论】:

    【解决方案2】:

    一个可能的答案(仅使用基本库)是

    import Data.Data
    import Data.Functor.Const
    
    length :: Data a => a -> Int
    length =
      getConst .
      gfoldl (\(Const c) _ -> Const (c+1)) (const 0)
    

    我最近在 London Haskell 就这个主题做了一个完整的演讲。幻灯片是here,但视频尚未发布。

    【讨论】:

    • 值得注意的是,这不仅会为元组提供“长度信息”,还会为各种其他数据结构提供“长度信息”,可能并不总是符合预期的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    相关资源
    最近更新 更多