gpt4 book ai didi

haskell - 记录中的多态类型

转载 作者:行者123 更新时间:2023-12-04 14:14:04 24 4
gpt4 key购买 nike

我正在尝试编写一个从文件中读取原始字节的函数,将其“转换”为“普通”类型,然后对其进行排序。

为了做到这一点,我需要告诉排序它应该如何解释二进制数据——即二进制数据的类型是什么。

为了使其成为“二进制”数据,在“我可以将这些数据视为原始位,因为我从磁盘读取和写入它”的意义上,数据的类型必须是二进制和位。
而且,要对其进行排序,它必须是 Ord 的成员。

任何受这些方式约束的类型都应该是可排序的。

作为一个小技巧,为了将类型传递给排序函数,我改为传递该类型的居民。 (如果有办法传递类型本身并获得结果,我很想知道。)

{-# LANGUAGE RankNTypes #-}

import Data.Binary.Get
import Data.Binary.Put

type Sortable = forall a. (Bits a, Binary a, Ord a) => a

data SortOpts = SortOpts { maxFiles :: Int
, maxMemory :: Integer
, maxThreads :: Int
, binType :: Sortable
}

defaultOpts = SortOpts { maxFiles = 128
, maxMemory = 1000 * 1000 * 1000 * 1000
, maxThreads = 4
, binType = 0 :: Word32
};

putBinaryValues :: Binary a => Handle -> [a] -> IO ()
putBinaryValues out vals = do
let bytes = runPut . mapM_ put $ vals
BL.hPut out bytes

binaryValues :: (Binary a, Bits a) => a -> Handle -> IO [a]
binaryValues t inf = do
size <- hFileSize inf
let cast = runGet (genericReplicateM (size `div` byteWidth) get)
cast . BL.fromChunks . (:[]) <$> BS.hGetContents inf
where genericReplicateM n = sequence . (DL.genericReplicate n)
byteWidth = fromIntegral $ (bitSize t) `div` 8

但这不会编译。显然,Haskell 坚持认为记录的所有值都是具体类型。至少,这就是我从错误消息中收集到的:
Could not deduce (a ~ Word32)
from the context (Bits a, Ord a, Binary a)
bound by a type expected by the context:
(Bits a, Ord a, Binary a) => a
at ...
`a' is a rigid type variable bound by
a type expected by the context: (Bits a, Ord a, Binary a) => a

那么,我怎样才能实现这种概括呢?

编辑:

我想使用记录更新语法来“配置”排序。例如。:
configure = defaultOpts -- and exporting that

然后
let myOpts = configure{ binType = 42 :: Word16 }

但这不起作用,我不太明白为什么,除非它只是 NYI。
Record update for insufficiently polymorphic field: binType :: a
In the expression: configure {binType = words !! 0}
In an equation for `o': o = configure {binType = words !! 0}
In the expression:
do { inTestHandle <- inTest;
words <- testRandomWords;
putBinaryValues inTestHandle $ take 100 words;
seekBeg inTestHandle;
.... }

那么,我的客户端代码是否只需将值从 defaultOpts 中复制出来,并在每次想要重新配置排序时创建一个新记录?

最佳答案

问题

问题是 RankNTypes .看Sortable , 它是一个返回任意 a 的函数, 其中 aOrd 的一个实例, Bits , 和 Bytes .换句话说,那里不仅有 3 个类的一个实例,还有所有实例。
Word32显然不能这样做,所以试图把它放在那里是错误的。

把它想象成 undefined , undefined不是“与 a 兼容的某些类型”,它可以是所有类型。这相当于说

foo :: a
foo = 1

如果你想要一些词汇: a是普遍量化的,所以调用者选择实现。您想要的是存在量化,被调用者选择具体类型。

可能的修复

所以最简单的补救措施是
data SortOpts a = SortOpts { 
maxFiles :: Int
, maxMemory :: Integer
, maxThreads :: Int
, binType :: a
}

和约束 a在每个功能上
 someFun :: (Bits a, Bytes a, Ord a) => SortOpts a -> whatever

为了方便打字,
 class (Ord a, Bytes a, Bits a) => Sortable a where
instance (Ord a, Bytes a, Bits a) => Sortable a where

否则,您将需要创建一个存在的“拳击”类型。这里我使用 GADT要做到这一点。
 {-# LANGUAGE GADTs #-}

data SortBox where
Sort :: (Bits a, Bytes a, Ord a) => a -> SortBox

然后创建 Bits 的实例, Bytes , 和 Ord只需将隐藏的 a 拆箱即可并对其进行操作。这让您可以使用 Sort 将任何类型装箱然后一般将其用作 Bits , Bytes , 或 Ord .它在类型级别是透明的,但在值级别您必须将奇怪的东西装箱。
data SortOpts a = SortOpts { 
maxFiles :: Int
, maxMemory :: Integer
, maxThreads :: Int
, binType :: SortBox
}

关于haskell - 记录中的多态类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18598236/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com