gpt4 book ai didi

Haskell - 类型包装器统一

转载 作者:行者123 更新时间:2023-12-02 15:53:43 25 4
gpt4 key购买 nike

我有很多功能,例如:

f1 :: String -> String -> ... -> String -> ()
f1 a b ... z = g [("a", a), ("b", b), ... ("z", z)]
...
fn :: String -> Int -> String -> ... -> String -> ()
fn a b ... z = g [("a", a), ("b", show b), ... ("z", z)]

所以用户可以像 f1 "abc" "def" 这样调用它们。我不希望他这样做,因为他很容易错误地交换“abc”和“def”(天知道调试时会浪费多少时间)。我希望他传递像 fk (A "abc") (B "def") 这样的参数据我所知,有两种选择:

  1. 大量data构造和大量解包功能:

    data Value = A String
    | B String
    | C Int
    | D String
    ...

    unpack :: Value -> String
    unpack (A a) = a
    unpack (B b) = b
    unpack (C c) = show c
    unpack (D c) = d

    大量代码。

  2. 常见类型类和新类型:
    编辑:好吧,我们可以使用 GeneralizedNewtypeDeriving在如此简单的情况下。

      {-# LANGUAGE GeneralizedNewtypeDeriving #-}

    class Value a where
    unpack :: a -> String
    instance Value String where
    unpack = id
    instance Value Int where
    unpack = show

    newtype A = A String deriving Value
    newtype B = B String deriving Value
    newtype C = C Int deriving Value
    newtype D = D String deriving Value

    ...

    看起来好多了,但是所有fk看起来像

       fk a b ... z = g [("a", unpack a), ("b", unpack b), ... ("z", unpack z)]

    大量代码和重复。

我想要的是一些魔术,它可以让我:

  1. fk a b ... z = g [("a", a), ("b", b), ... ("z", z)]
  2. g = h . map (second unpack)

最佳答案

我认为问题归结为:列表只能包含相同类型的元素;这意味着您要么必须将其“合并”为 f 中的单一类型,要么不能依赖 haskells 类型检查。例如。以下代码适合您,但类型检查是运行时的:

{-# LANGUAGE GADTs #-}

import Control.Arrow (second)

data Item where
A :: String -> Item
B :: Int -> Item

unpack (A s) = s
unpack (B i) = show i

myf a@(A {}) b@(B {}) c@(B {}) =
let g = [("a", a), ("b", b), ("c", c)]
in map (second unpack) g
myf _ _ _ = error "Bad types"

main = do
putStrLn $ show $ myf (A "test") (B 13) (B 14)
putStrLn $ show $ myf (A "test") (B 13) (A "xxx")

当你想要编译时类型检查时,你可以这样做;但是,您仍然必须将参数重新输入为相同的类型,因此从某种意义上说,解压它并没有太大区别,只是它可能稍微不太容易出错。一个很好的技巧来自 json 包 - 它们重新定义一些运算符(例如 =:)来创建类型,因此您将拥有:

{-# LANGUAGE ExistentialQuantification #-}
import Control.Arrow (second)

class Value a where
unpack :: a -> String
newtype A = A String
newtype B = B Int

instance Value A where
unpack (A a) = a

instance Value B where
unpack (B b) = show b

data Item = forall b. Value b => Item b
a =: b = (a, Item b)

myf :: A -> B -> B -> [(String, String)]
myf a b c =
let g = ["a" =: a, "b" =: b, "c" =: c]
in map (second (\(Item x) -> unpack x)) g

main = do
putStrLn $ show $ myf (A "test") (B 13) (B 14)

这与仅仅定义 a =: b = (a, unpack b) 没有太大区别。

关于Haskell - 类型包装器统一,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9087643/

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