我在 Haskell 中有一个任务(不,这不是我的作业,我正在为考试而学习)。
任务是:
Write point-free function
numocc
which counts occurrences of element in given lists. For example:numocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]]
=[1, 2, 0]
这是我的代码:
addif :: Eq a => a -> Int -> a -> Int
addif x acc y = if x == y then acc+1 else acc
count :: Eq a => a -> [a] -> Int
count = flip foldl 0 . addif
numocc :: Eq a => a -> [[a]] -> [Int]
numocc = map . count
numocc
和 count
是“无点”,但他们正在使用函数 addif
不是。我不知道如何执行
addif
功能免积分。有什么办法吗if
声明点免费?也许有一个使用 no if
的技巧?
最佳答案
我会使用您可以轻松转换 Bool
的事实。到 Int
使用 fromEnum
:
addif x acc y = acc + fromEnum (x == y)
现在您可以开始应用通常的技巧来使其无点
-- Go prefix and use $
addif x acc y = (+) acc $ fromEnum $ (==) x y
-- Swap $ for . when dropping the last argument
addif x acc = (+) acc . fromEnum . (==) x
等等。我不会带走让它变得免费的所有乐趣,尤其是当有工具可以为你做这件事的时候。
或者,您可以编写一个函数,例如
count x = sum . map (fromEnum . (==) x)
这几乎是免费的,并且有一些技巧可以让你更接近,尽管它们很快就会变得非常讨厌:
count = fmap fmap fmap sum map . fmap fmap fmap fromEnum (==)
在这里,我认为使用
fmap
实际上看起来更好。而不是 (.)
,尽管您可以替换每个 fmap
与 (.)
这将是完全相同的代码。本质上,(fmap fmap fmap)
将单个参数和两个参数函数组合在一起,如果您将其命名为 .:
你可以这样写count = (sum .: map) . (fromEnum .: (==))
分解:
> :t fmap fmap fmap sum map
Num a => (a -> b) -> [a] -> b
所以它从
b
获取一个函数到数字 a
,b
的列表s,并返回 a
,还不错。> :t fmap fmap fmap fromEnum (==)
Eq a => a -> a -> Int
而这个类型可以写成
Eq a => a -> (a -> Int)
,这是需要注意的重要一点。这使得该函数的返回类型与 fmap fmap fmap sum map
的输入相匹配。与 b ~ Int
, 所以我们可以将它们组合成 Eq a => a -> [a] -> Int
类型的函数.
关于haskell - 使函数与 'if' 无点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34342516/