问题
If I want to add a space at the end of a character to return a list, how would I accomplish this with partial application if I am passing no arguments?
Also would the type be?
space :: Char -> [Char]
I'm having trouble adding a space at the end due to a 'parse error' by using the ++ and the : operators.
What I have so far is:
space :: Char -> [Char]
space = ++ ' '
Any help would be much appreciated! Thanks
回答1:
Doing what you want is so common in Haskell it's got its own syntax, but being Haskell, it's extraordinarily lightweight. For example, this works:
space :: Char -> [Char]
space = (:" ")
so you weren't far off a correct solution. ([Char]
is the same as String
. " "
is the string containing the character ' '
.) Let's look at using a similar function first to get the hang of it. There's a function in a library called equalFilePath :: FilePath -> FilePath -> Bool
, which is used to test whether two filenames or folder names represent the same thing. (This solves the problem that on unix, mydir
isn't the same as MyDir
, but on Windows it is.) Perhaps I want to check a list to see if it's got the file I want:
isMyBestFile :: FilePath -> Bool
isMyBestFile fp = equalFilePath "MyBestFile.txt" fp
but since functions gobble their first argument first, then return a new function to gobble the next, etc, I can write that shorter as
isMyBestFile = equalFilePath "MyBestFile.txt"
This works because equalFilePath "MyBestFile.txt"
is itself a function that takes one argument: it's type is FilePath -> Bool
. This is partial application, and it's super-useful. Maybe I don't want to bother writing a seperate isMyBestFile
function, but want to check whether any of my list has it:
hasMyBestFile :: [FilePath] -> Bool
hasMyBestFile fps = any (equalFilePath "MyBestFile.txt") fps
or just the partially applied version again:
hasMyBestFile = any (equalFilePath "MyBestFile.txt")
Notice how I need to put brackets round equalFilePath "MyBestFile.txt"
, because if I wrote any equalFilePath "MyBestFile.txt"
, then filter
would try and use just equalFilePath
without the "MyBestFile.txt"
, because functions gobble their first argument first. any :: (a -> Bool) -> [a] -> Bool
Now some functions are infix operators - taking their arguments from before and after, like ==
or <
. In Haskell these are just regular functions, not hard-wired into the compiler (but have precedence and associativity rules specified). What if I was a unix user who never heard of equalFilePath
and didn't care about the portability problem it solves, then I would probably want to do
hasMyBestFile = any ("MyBestFile.txt" ==)
and it would work, just the same, because == is a regular function. When you do that with an operator function, it's called an operator section.
It can work at the front or the back:
hasMyBestFile = any (== "MyBestFile.txt")
and you can do it with any operator you like:
hassmalls = any (< 5)
and a handy operator for lists is :
. :
takes an element on the left and a list on the right, making a new list of the two after each other, so 'Y':"es"
gives you "Yes"
. (Secretly, "Yes"
is actually just shorthand for 'Y':'e':'s':[]
because :
is a constructor/elemental-combiner-of-values, but that's not relevant here.) Using :
we can define
space c = c:" "
and we can get rid of the c
as usual
space = (:" ")
which hopefully make more sense to you now.
回答2:
What you want here is an operator section. For that, you'll need to surround the application with parentheses, i.e.
space = (: " ")
which is syntactic sugar for
space = (\x -> x : " ")
(++)
won't work here because it expects a string as the first argument, compare:
(:) :: a -> [a] -> [a]
(++) :: [a] -> [a] -> [a]
来源:https://stackoverflow.com/questions/12548982/partial-application-of-operators