【问题标题】:Haskell function that counts input numbers and finds how many are equalHaskell 函数计算输入数字并找出有多少相等
【发布时间】:2016-03-15 11:41:33
【问题描述】:

我正在尝试在 Haskell 中编写一个函数,该函数将 4 个整数作为输入并计算输入数字中有多少等于第一个整数。

例如:

howManyEq 3 4 5 6   returns 0
howManyEq 3 4 3 5   returns 2
howManyEq 3 4 3 3   returns 3
howManyEq 3 3 3 3   returns 4

这是我到目前为止创建的函数,它适用于没有与第一个整数匹配的输入的第一个实例。但是当有其他匹配的整数时,它不计算前3个,它总是少一个。

howManyEq :: Int -> Int-> Int -> Int -> Int
howManyEq a b c d = count (head (toList a b c d)) (tail (toList a b c d))

count :: Int -> [Int] -> Int
count x [] = 0
count x (y:ys)
 | x == y = 1 + (count x ys)
 | otherwise = count x ys

toList :: Int -> Int-> Int -> Int -> [Int]
toList a b c d = [a,b,c,d]

我的功能给了我:

howManyEq 3 4 5 6   returns 0
howManyEq 3 4 3 5   returns 1
howManyEq 3 4 3 3   returns 2
howManyEq 3 3 3 3   returns 3

当其他输入整数相等时,我不确定如何计算第一个整数。

【问题讨论】:

  • 根据您的逻辑,howManyEq 永远无法返回 1. 创建将+ 1 返回到您现在返回的函数。将该结果输入定义为 f 1 = 0f a = a 的函数中...
  • 你的例子是不是不正确?不应该第一次返回1。如果是这种情况,这是一个典型的错误。
  • howManyEq 3 4 3 5 应该返回 2,因为它计算 3 的两个实例。但是 howManyEq 3 4 5 6 应该返回 0。我知道这有点不合逻辑,但这是我老师出于某种原因想要的方式。

标签: list function haskell input integer


【解决方案1】:

您的count 函数计算“列表”剩余部分中相等元素的数量。如果该数字为零,则您的老师希望结果为零。如果有一个或多个,它会返回列表剩余部分中计数的数量,但由于列表头部已经有一个元素,你应该做 +1。你可以通过实现一个辅助函数来做到这一点:

fix :: (Eq a, Num a) => a -> a
fix 0 = 0
fix n = n+1

现在您可以简单地将count 函数的结果通过fix 传递:

howManyEq :: Int -> Int-> Int -> Int -> Int
howManyEq a b c d = fix $ count (head (toList a b c d)) (tail (toList a b c d))

count :: Int -> [Int] -> Int
count x [] = 0
count x (y:ys)
 | x == y = 1 + (count x ys)
 | otherwise = count x ys

toList :: Int -> Int-> Int -> Int -> [Int]
toList a b c d = [a,b,c,d]

其他建议:

  • 您在调用中使用head (toList a b c d) 进行计数。但是你已经提前知道这是a,所以省略这个。

  • 与尾部相同:只需输入最后三个参数,因此:toList b c d

  • 尽可能使用最通用的类​​型签名:toList :: a -> a -> a -> [a](鉴于之前的修复)、count :: (Eq a, Num b) => a -> [a] -> bhowManyEq :: (Eq a, Eq b, Num b) => a -> a -> a -> a -> b

  • 如果你多次定义同一个东西,你可以使用where t = ...子句,比如where cys = count x ys

这将导致类似:

fix :: (Eq a, Num a) => a -> a
fix 0 = 0
fix n = n+1

howManyEq :: (Eq a, Eq b, Num b) => a -> a -> a -> a -> b
howManyEq a b c d = fix $ count a $ toList b c d

count :: (Eq a, Num b) => a -> [a] -> b
count x [] = 0
count x (y:ys)
 | x == y = 1 + cys
 | otherwise = cys
 where cys = count x ys

toList :: a -> a -> a -> [a]
toList a b c = [a,b,c]

【讨论】:

  • 是的,这正是我所需要的,谢谢。我会听取你的建议,让它更整洁,我没有意识到有些东西可以省略。
【解决方案2】:

这是一种方法:

{-# LANGUAGE TypeFamilies #-}

class HowManyEq a where
  howManyEq' :: Int -> Int -> Int -> a

instance HowManyEq Int where
  howManyEq' count x y = count + fromEnum (x == y)
  {-# INLINE howManyEq' #-}

instance (HowManyEq a, b ~ Int) => HowManyEq (b -> a) where
  howManyEq' count x y b = (howManyEq' $! count + fromEnum (b == x)) x y
  {-# INLINE howManyEq' #-}

howManyEq :: HowManyEq a => Int -> Int -> a
howManyEq = howManyEq' 0

howManyEq4 :: Int -> Int -> Int -> Int -> Int
howManyEq4 x y z w =
  case howManyEq x y z w of
    0 -> 0
    n -> n + 1

【讨论】:

  • 这让我想起了FizzBuzzEnterpriseEdition
  • @DanielWagner,为什么投反对票?还是那不是你的?
  • 我投了反对票,因为这个答案的预期受众和实际受众之间似乎存在严重的(并且,根据我的判断,是故意的)不匹配。
  • @DanielWagner,这种不匹配不是故意的。我对 Haskell 中可变参数函数的黑暗艺术几乎没有什么经验,我认为这是一个试一试的好机会。
  • 我欠你一个道歉。我对你的意图做出的判断是不必要的,也是不友善的。很抱歉我把它叫出来了,更抱歉我一开始就做到了。
猜你喜欢
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 2018-03-19
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
  • 1970-01-01
相关资源
最近更新 更多