无法使用点运算符编写Haskell函数

iro*_*ion -1 haskell

我正在写一个简单的函数来转换Integer为其各个数字的列表:

toDigits :: Integer -> [Integer]
toDigits 0 = [0]
toDigits n = [toInteger (digitToInt (show n !! x)) | x <- [0..(length (show n) - 1)]]
Run Code Online (Sandbox Code Playgroud)

我想链接

toInteger (digitToInt (show n !! x))

像点运算符一样:

toInteger . digitToInt . show . (!!) n x
Run Code Online (Sandbox Code Playgroud)

但是我觉得我对如何用点运算符编写这些函数有误解,因为这会产生难以理解的(对我的haskell-brain)类型错误

che*_*ner 5

当涉及多参数函数时,无点样式开始变得混乱.可以说,像

(toInteger . digitToInt) $ show n !! x
Run Code Online (Sandbox Code Playgroud)

更具可读性.请继续阅读以获取此表达式的无点版本的一些示例.


首先,show n !! x实际上是(!!) (show n) x(因为函数应用程序具有更高的优先级(!!)),所以你不能直接编写show(!!).相反,你可以写

toInteger (digitToInt ((!!) (show n) x))
Run Code Online (Sandbox Code Playgroud)

函数应用程序的优先级高于组合,因此您需要使用括号:

(toInteger . digitToInt . (!!)) (show n) x
Run Code Online (Sandbox Code Playgroud)

或者($)运算符,其优先级低于组合:

toInteger . digitToInt . (!!) $ (show n) x
Run Code Online (Sandbox Code Playgroud)

去有点疯狂,你可以使用flip部分地适用(!!)x第一,让你写

toInteger . digitToInt . (flip (!!)) x . show $ n
Run Code Online (Sandbox Code Playgroud)

去一点点疯狂,使用Control.Arrowuncurry定义,你可以应用到一个完全免费的点对点功能 (n, x)

toInteger . digitToInt . (first show >>> uncurry (!!)) $ (n, x)
Run Code Online (Sandbox Code Playgroud)

first show是一个带有一对(n, x)并返回的函数((show n), x).然后喂这对uncurry (!!); uncurry只需创建一个函数,该函数将一对作为输入而不是两个参数:

> :t (!!)
[a] -> Int -> a
> :t uncurry (!!)
([c], Int) -> c
Run Code Online (Sandbox Code Playgroud)