gpt4 book ai didi

haskell - 操作 "arbitrary"元组

转载 作者:行者123 更新时间:2023-12-03 14:40:07 27 4
gpt4 key购买 nike

我有简单的元组(例如从数据库中读取),我不知道元素的数量和内容。例如。(String, Int, Int)(String, Float, String, Int) .

我想编写一个通用函数,它将采用各种元组并用字符串“NIL”替换所有数据。如果字符串“NIL”已经存在,它应该保持不变。

回到例子:("something", 3, 4.788)应该导致 ("something", "NIL", "NIL")("something else", "Hello", "NIL", (4,6))应该导致 ("something else", "NIL", "NIL", "NIL")
我显然不知道从哪里开始,因为用已知的元组来做这件事不会有问题。在没有 Template Haskell 的情况下,是否有可能达到我想要的结果?

最佳答案

可以使用 GHC.Generics ,我想我会在这里记录它的完整性,尽管我不会推荐它而不是这里的其他建议。

这个想法是将你的元组转换成可以进行模式匹配的东西。典型的方法(我相信 HList 使用)是从 n 元组转换为嵌套元组:(,,,) -> (,(,(,))) .
GHC.Generics通过将元组转换为产品的嵌套应用程序来做类似的事情 :*:构造函数。 tofrom是将值与其通用表示形式相互转换的函数。元组字段一般由 K1 表示。 newtypes,所以我们想要做的是通过元数据树( M1 )和产品( :*: )节点向下递归,直到我们找到 K1叶节点(常量)并用“NIL”字符串替换它们的内容。
Rewrite type 函数描述了我们如何修改类型。 Rewrite (K1 i c) = K1 i String声明我们将用 c 替换每个值(String 类型参数) .

给定一个小测试应用程序:

y0 :: (String, Int, Double)
y0 = ("something", 3, 4.788)

y1 :: (String, String, String, (Int, Int))
y1 = ("something else", "Hello", "NIL", (4,6))

main :: IO ()
main = do
print (rewrite_ y0 :: (String, String, String))
print (rewrite_ y1 :: (String, String, String, String))

我们可以使用通用重写器来生成:
*Main> :main("something","NIL","NIL")("something else","NIL","NIL","NIL")

Using the built-in Generics functionality and a typeclass to do the actual transformation:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

import Data.Typeable
import GHC.Generics

rewrite_
:: (Generic a, Generic b, Rewriter (Rep a), Rewrite (Rep a) ~ Rep b)
=> a -> b
rewrite_ = to . rewrite False . from

class Rewriter f where
type Rewrite f :: * -> *
rewrite :: Bool -> f a -> (Rewrite f) a

instance Rewriter f => Rewriter (M1 i c f) where
type Rewrite (M1 i c f) = M1 i c (Rewrite f)
rewrite x = M1 . rewrite x . unM1

instance Typeable c => Rewriter (K1 i c) where
type Rewrite (K1 i c) = K1 i String
rewrite False (K1 x) | Just val <- cast x = K1 val
rewrite _ _ = K1 "NIL"

instance (Rewriter a, Rewriter b) => Rewriter (a :*: b) where
type Rewrite (a :*: b) = Rewrite a :*: Rewrite b
rewrite x (a :*: b) = rewrite x a :*: rewrite True b

还有一些本示例未使用的实例,其他数据类型需要它们:
instance Rewriter U1 where
type Rewrite U1 = U1
rewrite _ U1 = U1

instance (Rewriter a, Rewriter b) => Rewriter (a :+: b) where
type Rewrite (a :+: b) = Rewrite a :+: Rewrite b
rewrite x (L1 a) = L1 (rewrite x a)
rewrite x (R1 b) = R1 (rewrite x b)

稍加努力, Typeable可以从 K1 中删除约束例如,由于 Overlapping/UndecidableInstances,它是否更好是有争议的。 GHC 也无法推断结果类型,尽管它似乎应该可以。在任何情况下,结果类型都需要正确,否则您将收到难以阅读的错误消息。

关于haskell - 操作 "arbitrary"元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13436366/

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