gpt4 book ai didi

haskell - Variadic list appender 函数,用于从 haskell 中的列表中创建列表列表

转载 作者:行者123 更新时间:2023-12-02 08:03:46 25 4
gpt4 key购买 nike

我正在查看 this question了解如何获取多个列表并将它们变成列表的列表。我有以下内容:

Prelude> x1 = [1,2,3]
Prelude> x2 = [4,5,6]
Prelude> x3 = [7,8,9]

我希望看到一些\function 可以是可变的:

Prelude> xs = map (\function -> ???) x1 x2 x3
Prelude> show xs -- that produces this
[[1,2,3], [4,5,6], [7,8,9]]

或者没有 map ,一些其他可变参数函数 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

最佳答案

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

这不是太棒了。我们可以做得更好吗?


方法 2:类型类(需要 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 = []

我会留给你解决这个问题。


方法 3:函数依赖(需要 FlexibleInstancesFunctionalDependencies)

这是前一个版本的多态版本,我们必须通过函数依赖来跟踪类型。

{-# 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刚才的代码。


方法四:元编程(需要模板Haskell)

我认为这是理论上最不有趣的解决方案,所以我不会深入讨论那些坦率乏味的示例。

此方法涉及创建一个函数,该函数通过 Template Haskell 生成 Haskell 代码,然后可以在编译时根据此列表的长度使用该函数生成必要的函数。这本质上是方法 1 的劳动强度较低(但编译时速度较慢)的版本。


现在可能有更多的方法可以做到这一点,但我希望这些示例对您有所帮助,或者至少对您有所启发。

关于haskell - Variadic list appender 函数,用于从 haskell 中的列表中创建列表列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53972708/

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