如何将函数应用于异构列表中的一个元素?

时间:2015-03-11 14:02:18

标签: haskell

所以我试图找出最有效的方法来做以下事情(仍然是一个合理的初学者):

你有一个内部有不同类型的异构列表。在我的代码中,我使用了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"35.5但可能会被描述为相当难看!

1 个答案:

答案 0 :(得分:7)

如果您有5个项目,abcde,您唯一知道的就是他们拥有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之外还有另外两种方法,它们将通过存在量化,showsPrecshowList :: [a] -> ShowS来捕获。存在限定的showList完全没用,你唯一可以做的就是一遍又一遍地重复相同的元素(showList []showList [x]showList[x,x]等等)因为您无法证明任何其他项目具有相同的类型,可以将其放入列表中。如果您需要showsPrec,则不需要show,因为show = ($ "") . showsPrec 0