Haskell 类型族和虚拟参数

标签 haskell type-families

我做了一个类似于numpy的array的函数。它将列表转换为数组、列表列表转换为二维数组等。

它的工作原理如下:

ghci> arrFromNestedLists ["hello", "world"] :: Array (Int, (Int, ())) Char
array ((0,(0,())),(1,(4,()))) [((0,(0,())),'h'),((0,(1,())),'e'),((0,(2,())),'l'),((0,(3,())),'l'),((0,(4,())),'o'),((1,(0,())),'w'),((1,(1,())),'o'),((1,(2,())),'r'),((1,(3,())),'l'),((1,(4,())),'d')]

(Int, (Int, ())) 而不是 (Int, Int) 因为我不知道增加 a 长度的编程方法元组。 (附带问题:有这样的方法吗?)

它的编码很尴尬,我必须做一个“解决方法”(将虚拟参数传递给函数)才能使其工作。我想知道是否有更好的方法。

这是代码,其中包含一些丑陋的解决方法的详细信息:

{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, TypeFamilies #-}

type family ListOfIndex i a
type instance ListOfIndex () a = a
type instance ListOfIndex (Int, i) a = [ListOfIndex i a]

class Ix i => ArrConv i where
  acBounds :: a -> ListOfIndex i a -> (i, i)
  acFlatten :: i -> ListOfIndex i a -> [a]

acBounds“应该”是::ListOfIndex i a -> (i, i)。对于 acFlatten 也是如此。每个都给出一个虚拟变量(undefined 始终是给定的值),否则我无法编译它:(

arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists lst =
  listArray
  (acBounds (undefined :: a) lst)
  (acFlatten (undefined :: i) lst)

上面是在工作中传递的虚拟未定义参数。它告诉 GHC 使用 ListOfIndex 的哪个实例。

instance ArrConv () where
  acBounds _ = const ((), ())
  acFlatten _ = (: [])

下面的函数应该是 ArrConv 实例中的 acBounds 函数,并且在外部声明只是因为我需要使用 ScopedTypeVariables我不知道如何在实例定义的函数中做到这一点..

acSucBounds
  :: forall a i. ArrConv i
  => a -> [ListOfIndex i a] -> ((Int, i), (Int, i))
acSucBounds _ lst =
  ((0, inStart), (length lst - 1, inEnd))
  where
    (inStart, inEnd) = acBounds (undefined :: a) (head lst)

instance ArrConv i => ArrConv (Int, i) where
  acBounds = acSucBounds
  acFlatten _ = concatMap (acFlatten (undefined :: i))

最佳答案

acBounds 和 acFlatten 需要额外参数的原因是类型 ai 无法从 ListOfIndex i a -> (i, i)ListOfIndex i a -> [a] 分别。一种解决方法是将这两种方法合并为 ListOfIndex i a -> ((i, i), a) 类型的一个方法 acArgs。现在唯一的问题是在 (Int, i) 实例中使用它,以防止类型检查器过度泛化其类型,从而导致与以前相同的问题(例如,我们不能简单地使用fst.acArgs)。

{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

import Data.Array

type family ListOfIndex i a
type instance ListOfIndex () a = a
type instance ListOfIndex (Int, i) a = [ListOfIndex i a]

class Ix i => ArrConv i where
  acArgs :: ListOfIndex i a -> ((i, i), [a])

instance ArrConv () where
  acArgs x = (((), ()), [x])

instance ArrConv i => ArrConv (Int, i) where
  acArgs lst =
    (((0, inStart), (length lst - 1, inEnd)), args >>= snd)
    where
      args = map acArgs lst
      (inStart, inEnd) = fst (head args)

arrFromNestedLists :: ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists = uncurry listArray . acArgs

关于Haskell 类型族和虚拟参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2043610/

相关文章:

haskell - 在 Haskell 中使用相同的输入连接两个 IO 操作

haskell - 类型族内的多态函数

haskell - 未装箱类型的限制

haskell - 类型缩减无限循环

haskell - 在类型列表上映射依赖类型

haskell - Haskell 的 Erlang 等价物 where/partial/lambda

haskell - 结合持久化和 IO

design-patterns - 这种类似 monad 的函数式编程模式叫什么名字?

haskell - 如何将 TypeApplications 与 typeclass 方法一起使用,为什么 GHCi 会推断出我无法使用的类型?

haskell - 如何在没有 Do 符号的情况下写作