Haskell 中不带括号的链接参数
Chaining parameters without parentheses in Haskell
我正在尝试为 hnetcdf
库编写一个方便的包装器。我希望能够以简单的声明方式描述 NetCDF 文件结构,而不是处理其低级接口。为此,我创建了一堆 ADT:
data Info = Info FileInfo Dimentions Variables
data FileInfo = FileInfo String Int
data Dimentions = Dimentions [Dimention]
data Variables = Variables [Variable]
data Dimention = BoundedDimention String Int | UnboundedDimention String
data Variable = Variable String Int NC.NcType [Dimention]
如果我像下面的例子那样使用它们,它们就会起作用:
writeNetCDF :: FilePath -> IO ()
writeNetCDF filename = do
let dimX, dimY, dimZ = ...
let var1, var2 = ...
let info = Info (FileInfo filename 1)
(Dimentions [dimX, dimY, dimZ])
(Variables [var1, var2])
...
但我真的不喜欢额外的括号。我尝试使用 ($)
和 (.)
,但没有成功:
-- No way.
let info = Info $ FileInfo filename 1
$ Dimentions [dimX, dimY, dimZ]
$ Variables [var1, var2]
是否有另一种链接柯里化参数的方法?
当然可以。 $
在这种情况下的问题在于它是右结合的:
let info = Info $ FileInfo filename 1
$ Dimentions [dimX, dimY, dimZ]
$ Variables [var1, var2]
= Info ( FileInfo filename 1
( Dimentions [dimX, dimY, dimZ]
( Variables [var1, var2])
)
)
所以你只需要一个左结合运算符:
($<) :: (a -> b) -> a -> b
($<) = ($)
infixl 0 $< -- left associative
现在括号正确了:
let info = Info $< FileInfo filename 1
$< Dimentions [dimX, dimY, dimZ]
$< Variables [var1, var2]
= (
(
(Info
(FileInfo filename 1)
)
(Dimentions [dimX, dimY, dimZ])
)
(Variables [var1, var2])
)
let
和 where
子句都是递归计算的,所以你可以有这样的东西:
where
info = Info f dim vars
f = FileInfo filename 1
dim = Dimentions [dimX, dimY, dimZ]
vars = Variables [var1, var2]
$
运算符和.
运算符用于创建新函数。因此下面的表达式:
info = Info $ FileInfo filename 1
$ Dimentions [dimX, dimY, dimZ]
$ Variables [var1, var2]
说 Info 是一个类型构造函数,它接受 一个 参数,该类型由 FileInfo 类型返回,预计需要三个参数(filename
, 1
以及下一个名为 Dimentions
) 的函数返回的任何内容,依此类推。这根本不是你想要的。
.
运算符以数学方式将两个函数连接在一起 (f . g)(x)
等同于 f(g(x))
。再一次,这与您在此处尝试创建的内容完全不同。
我正在尝试为 hnetcdf
库编写一个方便的包装器。我希望能够以简单的声明方式描述 NetCDF 文件结构,而不是处理其低级接口。为此,我创建了一堆 ADT:
data Info = Info FileInfo Dimentions Variables
data FileInfo = FileInfo String Int
data Dimentions = Dimentions [Dimention]
data Variables = Variables [Variable]
data Dimention = BoundedDimention String Int | UnboundedDimention String
data Variable = Variable String Int NC.NcType [Dimention]
如果我像下面的例子那样使用它们,它们就会起作用:
writeNetCDF :: FilePath -> IO ()
writeNetCDF filename = do
let dimX, dimY, dimZ = ...
let var1, var2 = ...
let info = Info (FileInfo filename 1)
(Dimentions [dimX, dimY, dimZ])
(Variables [var1, var2])
...
但我真的不喜欢额外的括号。我尝试使用 ($)
和 (.)
,但没有成功:
-- No way.
let info = Info $ FileInfo filename 1
$ Dimentions [dimX, dimY, dimZ]
$ Variables [var1, var2]
是否有另一种链接柯里化参数的方法?
当然可以。 $
在这种情况下的问题在于它是右结合的:
let info = Info $ FileInfo filename 1
$ Dimentions [dimX, dimY, dimZ]
$ Variables [var1, var2]
= Info ( FileInfo filename 1
( Dimentions [dimX, dimY, dimZ]
( Variables [var1, var2])
)
)
所以你只需要一个左结合运算符:
($<) :: (a -> b) -> a -> b
($<) = ($)
infixl 0 $< -- left associative
现在括号正确了:
let info = Info $< FileInfo filename 1
$< Dimentions [dimX, dimY, dimZ]
$< Variables [var1, var2]
= (
(
(Info
(FileInfo filename 1)
)
(Dimentions [dimX, dimY, dimZ])
)
(Variables [var1, var2])
)
let
和 where
子句都是递归计算的,所以你可以有这样的东西:
where
info = Info f dim vars
f = FileInfo filename 1
dim = Dimentions [dimX, dimY, dimZ]
vars = Variables [var1, var2]
$
运算符和.
运算符用于创建新函数。因此下面的表达式:
info = Info $ FileInfo filename 1
$ Dimentions [dimX, dimY, dimZ]
$ Variables [var1, var2]
说 Info 是一个类型构造函数,它接受 一个 参数,该类型由 FileInfo 类型返回,预计需要三个参数(filename
, 1
以及下一个名为 Dimentions
) 的函数返回的任何内容,依此类推。这根本不是你想要的。
.
运算符以数学方式将两个函数连接在一起 (f . g)(x)
等同于 f(g(x))
。再一次,这与您在此处尝试创建的内容完全不同。