我在 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 -> cg :: c -> d (我的意思是说 c两个签名中的 s 类型相同,因此我并没有真正在这里编写正确的 Haskell 签名)。因为人们常常喜欢思考 f 作为“两个变量的函数”,人们可能会犯错误并想到 g . f 作为函数 \x y -> g (f x y) (类型 a -> b -> d)。不是这种情况:参见示例 这个问题及其答案 或具体示例 这个答案。 或者甚至更好:看着 的类型 (.) 并找出什么 g . f 一定是你自己!(暗示: 每个函数都精确地 争论. 。是什么类型的 f是一个论点吗?)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top