0

我在 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

谢谢!

4

2 回答 2

2

这不是部分应用,而是功能组合不起作用。您不能将 2 个参数传递给作为函数组合一部分的函数。

于 2013-11-15T15:47:39.310 回答
1

首先要注意的是 的签名getLines。既然p `isPrefixOf` 有类型(Eq a) => [a] -> BoolgetLines p就有类型(Eq a) => [[a]] -> [[a]](基于 的类型filter)。这里[a]似乎是String,所以getLines p有类型[String] -> [String]p因此似乎有类型String。所以实际上,getLines有类型String -> [String] -> [String]

最后,headhas (specialized) type [String] -> String,你正试图用getLines. 我猜你正在尝试构建一个由 typeString -> [String] -> String定义的函数\p ss -> head (getLines p ss)。然而,这不是什么head . getLines

要看到这一点,请考虑f :: a -> b -> cand g :: c -> d(我的意思是说cs 在两个签名中都是相同的类型,所以我并不是真的在这里写正确的 Haskell 签名)。由于人们经常喜欢将其f视为“两个变量的函数”,因此可能会犯错并将其g . f视为函数\x y -> g (f x y)(类型a -> b -> d)。情况并非如此:例如,请参阅此问题及其答案或此答案中的具体示例甚至更好:查看类型 (.)并找出g . f必须是您自己的类型!(提示:每个函数都只接受一个参数。 的一个参数的类型是什么f?)

于 2013-11-15T15:47:02.967 回答