Haskell型包装器
我有一系列函数,如:Haskell型包装器,haskell,Haskell,我有一系列函数,如: 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 :: 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”)
据我所知,有两种选择:
数据
构造和海量解包功能:
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
很多代码编辑:好的,我们可以在这种简单的情况下使用
generalizednewtypedering
{-# 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)]
大量的代码和重复fk a b。。。z=g[(“a”,a),(“b”,b),…(“z”,z)]
g=h。地图(第二次解包)
我认为问题可以归结为:列表只能有相同类型的元素;这意味着要么您必须在
f
中将其“合并”为单个类型,要么您不能依赖Haskell的类型检查。例如,以下代码适用于您,但类型检查是运行时的:
{-# 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)
没有太大区别