为什么 Haskell 部分应用程序不工作?
-
20-12-2019 - |
题
我在 Haskell 中的工作是为了获得乐趣而在 Haskell 中重新设计 .Net F# 项目。
我正在解析一个常规的 Windows 配置文件——每行一个键/值对,键与值之间通过 =
. 。这个文件非常简单直接,这让我的解析代码变得简单直接,这是我喜欢的。
我的问题是为什么部分应用程序在下面的最后一行代码上不起作用。显然它在之前的线路和其他功能中发挥着作用。
module Configuration (Config (..), load) where
import Data.Char (isSpace)
import Data.List (isPrefixOf)
data Config = Config { aliases :: [String]
, headers :: [String] }
-- This is a naive implementation. I can't decide if I like it better than
-- trim = unpack . strip . pack.
trim :: String -> String
trim = reverse . dropSpaces . reverse . dropSpaces
dropSpaces :: String -> String
dropSpaces = dropWhile isSpace
split _ [] = []
split c cs = [takeWhile (/= c) cs] ++ split c (tail' $ dropWhile (/= c) cs)
where tail' [] = []
tail' (x:xs) = xs
load :: String -> Config
load text =
let ss = lines text
hs = map getValue $ getLines "Header" ss
as = split ',' $ getValue $ getLine "AliasList" ss
in Config { aliases=as, headers=hs }
where getLines p = filter (p `isPrefixOf`)
getValue = trim . drop 1 . dropWhile (/= '=')
getLine = head . getLines -- Why isn't partial application working here?
我收到的错误如下:
Configuration.hs:30:29:
Couldn't match expected type `[c0]'
with actual type `[[a0]] -> [[a0]]'
Expected type: [a0] -> [c0]
Actual type: [a0] -> [[a0]] -> [[a0]]
In the second argument of `(.)', namely `getLines'
In the expression: head . getLines
谢谢!
解决方案
这不是部分应用不起作用,而是函数组合不起作用。您不能将 2 个参数传递给作为函数组合一部分的函数。
其他提示
首先要注意的是签名 getLines
. 。自从 p `isPrefixOf`
有类型 (Eq a) => [a] -> Bool
, getLines p
有类型 (Eq a) => [[a]] -> [[a]]
(根据类型 filter
)。这里 [a]
似乎是 String
, , 所以 getLines p
有类型 [String] -> [String]
和 p
因此似乎有类型 String
. 。所以事实上, getLines
有类型 String -> [String] -> [String]
.
最后, head
有(专门)类型 [String] -> String
, ,并且您尝试使用后合成 getLines
. 。我猜你正在尝试构建一个具有类型的函数 String -> [String] -> String
, , 被定义为 \p ss -> head (getLines p ss)
. 。然而,也就是说, 不是 什么 head . getLines
是!
要看到这一点,请考虑 f :: a -> b -> c
和 g :: c -> d
(我的意思是说 c
两个签名中的 s 类型相同,因此我并没有真正在这里编写正确的 Haskell 签名)。因为人们常常喜欢思考 f
作为“两个变量的函数”,人们可能会犯错误并想到 g . f
作为函数 \x y -> g (f x y)
(类型 a -> b -> d
)。不是这种情况:参见示例 这个问题及其答案 或具体示例 这个答案。 或者甚至更好:看着 的类型 (.)
并找出什么 g . f
一定是你自己!(暗示: 每个函数都精确地 一 争论. 。是什么类型的 f
是一个论点吗?)