所以我试图找出最有效的方法来做以下事情(仍然是一个合理的初学者):
你有一个内部有不同类型的异构列表。在我的代码中,我使用了Show
。我想要实现的是在显示它之后对该列表中的一个元素执行某些操作。目前你会写(天真)
[show a, show b, (++) " " $ show c, show d, show e]
是否有某种方法可以将函数(++) " "
打包为值c
,这样就可以编写类似
map show [a, b, inverseShow ((++) " ") c, d, e] -- not real haskell
或者这种语言不可能吗?
我知道你可以使用存在量词来获得分数
data ShowBox = forall s. Show s => SB s
instance Show ShowBox where show (SB s) = show s
map show [SB a, SB b, SB c, SB d, SB e]
但是我很难在“最佳实践”中努力了解如何从此转变为我想要的功能。方式是什么?
编辑:在阅读下面的评论后,我几乎得出结论,这不是编写代码的最佳方式。下面是我想要的行为的实现:
{-# LANGUAGE ExistentialQuantification #-}
data ShowAndTell = forall s. Show s => STell s (String -> String)
instance Show ShowAndTell where show (STell s f) = f $ (show s)
st :: (Show a) => a -> ShowAndTell
st a = STell a id
addSpace :: String -> String
addSpace x = x ++ " "
main = (mapM_ putStrLn) . (map show) $ [st "1", st 3, STell 5.5 addSpace]
这会输出"1"
,3
,5.5
但可能会被描述为相当难看!
答案 0 :(得分:7)
如果您有5个项目,a
,b
,c
,d
和e
,您唯一知道的就是他们拥有Show
个实例,您可以在列表中show
之前将所有关于它们的†放在列表中。
items :: [String]
items = [show a, show b, show c, show d, show e]
如果你想对列表的不同元素做不同的事情,比如在第三个元素之前添加一个空格,你可以列出要做的不同事情。
changes :: [String -> String]
changes = [id, id, (++) " ", id, id]
然后将changes
应用于列表中的items
,将两个列表压缩在一起,将更改应用于$
)。
changed :: [String]
changed = zipWith ($) changes items
†从技术上讲,Show
除了show
之外还有另外两种方法,它们将通过存在量化,showsPrec
和showList :: [a] -> ShowS
来捕获。存在限定的showList
完全没用,你唯一可以做的就是一遍又一遍地重复相同的元素(showList []
,showList [x]
,showList[x,x]
等等)因为您无法证明任何其他项目具有相同的类型,可以将其放入列表中。如果您需要showsPrec
,则不需要show
,因为show = ($ "") . showsPrec 0
。