【问题标题】:Multiplying elements in custom lists in HaskellHaskell中自定义列表中的元素相乘
【发布时间】:2020-04-18 00:41:52
【问题描述】:

我正在尝试在 Haskell 中为我的自定义列表数据类型实现自定义乘法运算,它使用 Int[Int]
Int 用于通过模除法来减少整数,我将其称为d.
[Int]代表列表的内容

假设ab 是两个具有相同d 的列表。
a的长度是wb的长度是v

c = a*b 是:

c[k] = a[0] * b[k] + a[1] * b[k - 1] + a[2] * b[k - 2] + · · · + a[k] * b[0]

最后,c[k] 减少了 mod d
c = w + v - 1的长度

意思是c[k]中的索引k可以大于wv的长度。
为了解决这个问题,我为原始列表边界之外的索引连接了一个 0 元素列表。

澄清一下:

c[0] = (a[0] * b[0]) % d  
c[1] = (a[0] * b[1] + a[1] * b[0]) % d  
c[2] = (a[0] * b[2] + a[1] * b[1] + a[2] * b[0]) % d  
.  
.  
.  
c[w + v - 1]

例如,a = [3,2,4]b = [7,9,7,2],两者都有 d = 31

在代码中,当它们相乘时,它们是 [3,2,4,0,0,0][7,9,7,2,0,0]

在此示例中,c = a * b = [21, 10, 5, 25, 1, 8]

这是我的代码:

module Custom where

    data CustomList = CustomList Int [Int]
    instance Num CustomList where
        (CustomList a1 b1) * (CustomList a2 b2) = 
            if length b1 >= 1 && length b2 >= 1  then do 
                let llen = (length b1) + (length b2) - 1

                --concatenating a list of 0 elements for indices outside the bounds of the original list. 
                let sub_b1 = llen - (length b1)
                let sub_b2 = llen - (length b2)
                let zeros_b1 = map (0*) [1..sub_b1]
                let zeros_b2 = map (0*) [1..sub_b2]

                --matching list lengths
                let new_b1 = b1++zeros_b1
                let new_b2 = b2++zeros_b2

                --trying to mimic a nested for loop
                let ans = [ (new_b1 !! x) * (new_b2 !! y) | x <- [0..llen-1], y <- (reverse [0..x]) ]

                CustomList (a1) (map (`mod` (a1)) ans)
            else do
                0

    instance Show CustomList where
        show (CustomList a b) = "output: " ++ (show b) ++ "\nlength: " ++ (show a)

输出:

*Custom> let a = CustomList 31 [3,2,4]  
*Custom> let b = CustomList 31 [7,9,7,2]  

不正确(我得到的)

*Custom> a * b  
output: [21,18,14,28,5,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]  
length: 31  

正确(我应该得到什么)

output: [21, 10, 5, 25, 1, 8]  
length: 6  

我意识到我的逻辑有问题:

  1. x 计数器,对于所有c[k] 计算,我需要从a[0] 开始并以a[k] 结束,但我从a[x] 开始。
  2. 未将答案汇总在一起。例如,我没有获得c[1] = a[0] * b[1] + a[1] * b[0],而是获得c[1] = a[0] * b[1] & c[2] = a[1] * b[0]

我不知道如何解决它,我一直在尝试,但最终只是通过尝试来制造新问题。

我是 Haskell 的新手,所以我更喜欢用简单易读的方法来解决这个问题,而不是更“Haskell”的方法。 但任何帮助表示赞赏,在此先感谢。

【问题讨论】:

    标签: haskell functional-programming


    【解决方案1】:

    又好又简单:

    data CustomList = CustomList Int [Int] deriving(Show)
    
    instance Num CustomList where
      CustomList a1 b1 * CustomList a2 b2 = CustomList a1 (map (`mod` a1) ans)
        where ans = map getAnsElem [1..length b1 + length b2 - 1]
              getAnsElem k = sum $ zipWith (*) (withLength k b1) (reverse $ withLength k b2)
              withLength n xs = take n (xs ++ repeat 0)
    

    测试它:

    λ> CustomList 31 [3,2,4] * CustomList 31 [7,9,7,2]
    CustomList 31 [21,10,5,25,1,8]
    

    解释:

    • withLength 获取一个列表并将其设置为给定长度,如果它太长则截断它,如果它太短则用零填充
    • zipWith 获取 2 个列表并并行遍历它们,使用给定的函数来组合元素
    • 使用列表理解的方法失败的一个原因是[f x y | x &lt;- xs, y &lt;- ys] 采用了xsys 的笛卡尔积而不是压缩它们。如果您想改用列表推导式,则可以,但您需要 ParallelListComp 扩展名,在这种情况下,您需要:
    getAnsElem k = sum [x * y | x <- withLength k b1 | y <- reverse $ withLength k b2]
    

    注意第二个| 而不是,:这就是压缩的意思。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-21
      • 2017-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多