简体   繁体   English

Haskell统计列表类型

[英]Haskell counted list type

So, just for fun, I've been playing with a CountedList type in Haskell, using Peano numbers and smart constructors . 所以,为了好玩,我一直在使用Peano数字和智能构造函数在Haskell中使用CountedList类型。

Type-safe head and tail just seem really cool to me. 对我来说,类型安全的headtail看起来真的很酷。

And I think I've reached the limit of what I know how to do 我想我已达到了解我该怎么做的极限

{-# LANGUAGE EmptyDataDecls #-}
module CountedList (
  Zero, Succ, CountedList,
  toList, ofList, 
  empty, cons, uncons, 
  head, tail, 
  fmap, map, foldl, foldr, filter
) where

import qualified List (foldr, foldl, filter)
import Prelude hiding (map, head, foldl, foldr, tail, filter)

data Zero
data Succ n
data CountedList n a = CL [a]

toList :: CountedList n a -> [a]
toList (CL as) = as

ofList :: [a] -> CountedList n a
ofList [] = empty
ofList (a:as) = cons a $ ofList as

empty :: CountedList Zero a
empty = CL []

cons :: a -> CountedList n a -> CountedList (Succ n) a
cons a = CL . (a:) . toList

uncons :: CountedList (Succ n) a -> (a, CountedList n a)
uncons (CL (a:as)) = (a, CL as)

head :: CountedList (Succ n) a -> a
head = fst . uncons

tail :: CountedList (Succ n) a -> CountedList n a
tail = snd . uncons

instance Functor (CountedList n) where
  fmap f = CL . fmap f . toList

map :: (a -> b) -> CountedList n a -> CountedList n b
map = fmap

foldl :: (a -> b -> a) -> a -> CountedList n b -> a
foldl f a = List.foldl f a . toList

foldr :: (a -> b -> b) -> b -> CountedList n a -> b
foldr f b = List.foldr f b . toList

filter :: (a -> Bool) -> CountedList n a -> CountedList m a
filter p = ofList . List.filter p . toList

(sorry for any transcription errors - the machine I originally wrote this on w/ my Haskell compiler is currently down). (对不起任何转录错误 - 我最初用我的Haskell编译器写的这台机器目前已经关闭了)。

Most of what I've done compiles w/o an issue, but I run into issues with ofList and filter . 我所做的大多数编译都没有编译问题,但是我遇到了ofListfilter问题。 I think I understand why - when I say ofList :: [a] -> CountedList na , I'm saying ofList :: forall n . [a] -> CountedList na 我想我理解为什么 - 当我说ofList :: [a] -> CountedList na ,我说的是ofList :: forall n . [a] -> CountedList na ofList :: forall n . [a] -> CountedList na - that the list created can be of any desired count type. ofList :: forall n . [a] -> CountedList na - 创建的列表可以是任何所需的计数类型。 What I want to write is the equivalent of the pseudo type ofList :: exists n . [a] -> CountedList na 我想写的是相当于伪类型的ofList :: exists n . [a] -> CountedList na ofList :: exists n . [a] -> CountedList na , but I don't know how. ofList :: exists n . [a] -> CountedList na ,但我不知道怎么做。

Is there a workaround that would let me write ofList and filter functions like I'm imagining, or have I reached the limit of what I can do with this? 是否有一种解决方法可以让我编写像我想象的ofListfilter函数,或者我是否达到了我可以用它做的限制? I have a sense that there's some trick with existential types that I'm missing. 我有一种感觉,就是存在一些我缺少的存在类型的技巧。

You can't write 你不能写

ofList :: [a] -> (exists n. CountedList n a)  -- wrong

but you can write 但你可以写

withCountedList :: [a] -> (forall n. CountedList n a -> b) -> b

and pass it a function which represents what you would have done with the result of ofList , as long as its type is independent of the length of the list. 并传递一个函数,该函数表示你对ofList的结果所做的ofList ,只要它的类型与列表的长度无关。

By the way, you can ensure the invariant that the type of a list corresponds to its length in the type system, and not rely on smart constructors: 顺便说一句,您可以确保列表类型与类型系统中的长度相对应的不变量,而不是依赖于智能构造函数:

{-# LANGUAGE GADTs #-}

data CountedList n a where
    Empty :: CountedList Zero a
    Cons :: a -> CountedList n a -> CountedList (Succ n) a

You can't define ofList or filter this way because they are confounding type-level checks with run-time values. 您无法定义ofList或以这种方式filter因为它们使用运行ofList混淆了类型级别检查。 In particular, in the type of the result, CountedList na , the type n must be determined at compile time. 特别是,在结果类型中, CountedList na ,类型n必须在编译时确定。 The implied desire is that n should be commensurate with the length of the list that is the first argument. 隐含的愿望是n应该与作为第一个参数的列表的长度相称。 But that clearly can't be known until run-time. 但是直到运行时才明白这一点。

Now, it might be possible to define a typeclass, say Counted, and then (with the appropriate Haskell extension), define these like: 现在,有可能定义类型类,比如计数,然后(使用适当的Haskell扩展),定义如下:

ofList :: [a] -> (forall n. (CountedListable CountedList n) => CountedList n a)

But you'd have a hard time doing anything with such a result, since the only operations that CountedListable could support would be extracting the count. 但是你很难用这样的结果做任何事情,因为CountedListable可以支持的唯一操作就是提取计数。 You couldn't, say get the head of such a value because head couldn't be defined for all instances of CountedListable 你不能,比如得到这样一个值的head ,因为无法为所有CountedListable实例定义头

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM