我正在寻找this question,以了解如何获取多个列表并将其转换为列表列表。我有以下内容:
Prelude> x1 = [1,2,3]
Prelude> x2 = [4,5,6]
Prelude> x3 = [7,8,9]
我想看一些\ variable的函数:
Prelude> xs = map (\function -> ???) x1 x2 x3
Prelude> show xs -- that produces this
[[1,2,3], [4,5,6], [7,8,9]]
或者没有地图,还有其他可变参数函数F,例如:
Prelude> xs = F x1 x2 x3 ... x1000
Prelude> show xs -- that produces this
[[1,2,3], [4,5,6], [7,8,9], ...., [1000000,1000001,1000002]]
我对答案的期望是
Prelude> map (:) x1 x2 x3 []
<interactive>:26:1: error:
• Couldn't match expected type ‘[Integer]
-> [Integer] -> [a0] -> t’
with actual type ‘[[Integer] -> [Integer]]’
• The function ‘map’ is applied to five arguments,
but its type ‘(Integer -> [Integer] -> [Integer])
-> [Integer] -> [[Integer] -> [Integer]]’
has only two
In the expression: map (:) x1 x2 x3 []
In an equation for ‘it’: it = map (:) x1 x2 x3 []
• Relevant bindings include it :: t (bound at <interactive>:26:1)
或
Prelude> map (:) $ x1 x2 x3 []
<interactive>:27:11: error:
• Couldn't match expected type ‘[Integer]
-> [Integer] -> [a0] -> [a]’
with actual type ‘[Integer]’
• The function ‘x1’ is applied to three arguments,
but its type ‘[Integer]’ has none
In the second argument of ‘($)’, namely ‘x1 x2 x3 []’
In the expression: map (:) $ x1 x2 x3 []
• Relevant bindings include
it :: [[a] -> [a]] (bound at <interactive>:27:1)
我也没有在Hoogle中找到这种功能,但是可能错误指定了类型签名:
https://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+%5Ba%5D+-%3E+%5B%5Ba%5D%2C%5Ba%5D%5D
答案 0 :(得分:4)
Haskell中的多元函数很难实现。这是因为一个函数从根本上只能有一个参数,因此只能通过currying来包含更多参数,这会将参数的数量烘焙到该函数的类型中。
但是,这并不意味着不可能,尽管有时候这需要使用扩展名。在这里,我将按复杂度递增的顺序进行一些操作。这可能不会很有用,但可能会有所帮助。
几年前我切切地做了a respository of examples of polyvariadic functions,您可能会发现它很有趣,但是它们的质量和质量都差不多。我什至现在都不专业,那是几年前的。
一种简单但粗略的方法是简单地定义多个函数以创建包含 n 个元素的列表,例如:
makeList1 :: a -> [a]
makeList2 :: a -> a -> [a]
-- etc.
-- Use:
myList = makeList5 1 2 3 4 5
这不是那么好。我们可以做得更好吗?
FlexibleInstances
)这更有趣。在这里,我们牺牲了特异性以创建真正的多元函数:
{-# LANGUAGE FlexibleInstances #-}
class MkIntList r where
mkIntList' :: [Int] -> r
-- No arguments
instance MkIntList [Int] where
mkIntList' = id
-- One argument, then some others
instance (MkIntList r) => MkIntList (Int -> r) where
mkIntList' xs x = mkIntList' (xs ++ [x]) -- (Inefficient, but this is an illustration)
-- The variadic function
mkIntList :: (MkIntList r) => r
mkIntList = mkIntList []
-- Use:
myList1 = mkIntList 1 2 3 :: [Int] -- myList1 = [1,2,3]
myList2 = mkIntList :: [Int] -- myList2 = []
我会离开你的脑袋。
FlexibleInstances
和FunctionalDependencies
)这是上一个版本的多态版本,在该版本中,我们必须通过功能依赖项来跟踪类型。
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
class MkList a r | r -> a where
mkList' :: [a] -> r
instance MkList a [a] where
mkList' = id
instance (MkList a r) => MkList a (a -> r) where
mkList' xs x = mkList' (xs ++ [x]) -- (Again inefficient)
mkList :: (MkList a r) => r
mkList = retList []
-- Use:
myList1 = mkList 'H' 'i' '!' :: String -- myList1 = "Hi!"
myList2 = mkList True False :: [Bool] -- myList2 = [True, False]
我不久前做了一个more efficient version of this代码。
我认为这是解决方案中理论上最不有趣的,所以我将不涉及坦率乏味的示例。
此方法涉及创建一个函数,该函数依次通过Template Haskell生成Haskell代码,然后可以在编译时根据此列表的长度使用该函数生成必要的函数。从本质上讲,这是方法1的劳动强度较小(但在编译时较慢)的版本。
如今,可能有更多的方法可以执行此操作,但是我希望您对这些示例有所帮助,或者至少可以启发人。
答案 1 :(得分:2)
主要是,您的方法不起作用的原因是(我认为)您对map
的理解有些误解。让我们看一下类型签名:
map :: (a -> b) -> [a] -> [b]
您可以在此处看到map
的主要限制是仅将一个列表作为参数传递-因此您不能传递多个列表,这是您尝试做的。另一个无效的原因是map
专门用于将函数应用到列表中 内的元素,而您正尝试在之间使用它>多个列表,而无需更改单个元素。
那么如何定义函数?这里的问题是Haskell并不真正支持可变参数功能(但请参见下文)。在Haskell中,如果要支持任意数量的相同类型的参数,则可以将它们连接到一个列表中。也就是fn [a, b, c]
而不是fn a b c
。因此,让我们在这里尝试:您的函数将是:
fn :: [[a]] -> [[a]]
fn = ???
那么我们如何实现呢?我们想要的是一个包含多个列表的函数,并且为我们提供了一个包含多个列表(参数)的列表,因此...输出与输入完全相同!在这一点上,我们最好忽略fn
-或实际上任何尝试的map (:)
组合-自己编写列表。因此,您的示例将是:
xs = [x1, x2, x3]
如果即使这对您都不起作用,并且您确实希望使用可变参数功能,那么我建议您回顾一下程序并检查其是否使用了最佳/最简便的方法-请记住XY problem。
(附带说明:如果您真的需要它,而没有其他方法来解决您的问题,那么实际上可以在Haskell中定义可变函数-搜索Haskell variadic function
,以获取更多信息。但是,这种方法在进行字符串格式设置或高级类型级别的东西时最有用,因此不太可能需要这种方法。