I understand that in Haskell it's important to put the most 'variable' argument (aka the input object) last in a function definition, to make the function as composable as possible (reference). But if I'm using a library function that doesn't follow this rule, is there any alternative/workaround to function composition to increase readability?
I'll give a specific example - the subRegex function takes the input string as the first of two arguments, and so chaining two of these plus a toUpper to create a "slugify" function I have ended up with the below:
slugify :: FilePath -> FilePath
slugify old =
let (dir, file) = splitFileName old
in combine dir $ subRegex (mkRegex "[ _]") (subRegex (mkRegex "[^.a-z0-9_ ]+") (map toLower file) "") "-"
Is there a function-composition-style way of tidying this up given the order of the subRegex arguments?
You can always provide a small helper to change the argument order into something more composable:
slugify :: FilePath -> FilePath
slugify old =
let (dir, file) = splitFileName old
in combine dir $ sub "[ _]" "-" $ sub "[^.a-z0-9_ ]+" "" $ map toLower file
where
sub regex replacement input = subRegex (mkRegex regex) input replacement
In simple cases, you can also use flip or a lambda expression, but in this case I think a local definition is nicer. It also makes it easy to remove the duplication of the calls to mkRegex.
Related
I have a config.cfg file where a the variable file_list is a list of relative path to files
file_list = file1 dir1/file2 ../dir2/file3
How do I read this variable in to get a file_list::[FilePath]?
Tried to follow the Development.Shake.Config API Doc without success. I need something to achieve that
file_list <- getConfig "file_list"
let fl = ??? file_list
need fl
ps. I'am an Haskell beginner
The type of file_list is Maybe String, and the type of fl needs to be [FilePath], so the question becomes how to write a function to transform between the two. One option is:
let fl = words (fromMaybe "" file_list)
The fromMaybe function replaces Nothing with "" - so you now have a String. The words function splits a string on the spaces, to produce [String]. In Haskell FilePath is a synonym for String so it all works out.
If instead you want to error out if the key is missing, you can do:
Just file_list <- getConfig "file_list"
let fl = words file_list
need fl
Now you are asserting and unwrapping the Maybe in file_list, so if it is Nothing you get a runtime crash, and if it is Just you get it without the Just wrapper, so can simply use words.
** old**
Suppose we have a pattern ex. "1101000111001110".
Now I have a pattern to be searched ex. "1101". I am new to Haskell world, I am trying it at my end. I am able to do it in c but need to do it in Haskell.
Given Pattern := "1101000111001110"
Pattern To Be Searched :- "110
Desired Output:-"Pattern Found"`
** New**
import Data.List (isInfixOf)
main = do x <- readFile "read.txt"
putStr x
isSubb :: [Char] -> [Char] -> Bool
isSubb sub str = isInfixOf sub str
This code reads a file named "read", which contains the following string 110100001101. Using isInfixOf you can check the pattern "1101" in the string and result will be True.
But the problem is i am not able to search "1101" in the string present in "read.txt".
I need to compare the "read.txt" string with the user provided string. i.e
one string is their in the file "read.txt"
and second string user will provid (user defined) and we will perform search and find whether user defined string is present in the string present in "read.txt"
Answer to new:
To achieve this, you have to use readLn:
sub <- readLn
readLn accepts input until a \n is encountered and <- binds the result to sub. Watch out that if the input should be a string you have to explicitly type the "s around your string.
Alternatively if you do not feel like typing the quotation marks every time, you can use getLine in place of readLn which has the type IO String which becomes String after being bound to sub
For further information on all functions included in the standard libraries of Haskell see Hoogle. Using Hoogle you can search functions by various criteria and will often find functions which suit your needs.
Answer to old:
Use the isInfixOf function from Data.List to search for the pattern:
import Data.List (isInfixOf)
isInfixOf "1101" "1101000111001110" -- outputs true
It returns true if the first sequence exists in the second and false otherwise.
To read a file and get its contents use readFile:
contents <- readFile "filename.txt"
You will get the whole file as one string, which you can now perform standard functions on.
Outputting "Pattern found" should be trivial then.
While studying for a Functional Programming exam, I came across the following question from a previous test:
t1 = (reverse . take 2 . words . \ _ -> name)"!"
The task is to write the output of the statement. The variable name refers to the student's name, written in the form "Smith, John". If I enter the statement into WinHugs, I get the following output:
["John","Smith,"]
I understand what the functions reverse, take and words are doing and I understand how the . operator connects them. What I don't understand is what is happening here:
\ _ -> name
What are the slash, underscore and "arrow" for? Also, what does the exclamation point in quotation marks do? (nothing?)
It's a lambda function that discards its (only) argument (i.e. "!") and yields name.
As another lambda example, the following would be a lambda function that squares its argument:
\x -> x * x
The \ is the notation used to introduce a lambda function.
The _ means "variable about whose name we do not care".
The -> separates the lambda function's arguments from the expression used to specify its result.
What you are seeing there is an anonymous function, or lambda function (that name comes from lambda calculus). The backslash tells you that you are starting the function. The underscore says that the function takes one argument and ignores it. The arrow points from the argument list to the result - in this case, it ends up ignoring its argument and returning the name. Essentially, \_ -> name is the same as const name.
A constant anonymous function: which ever the argument, return name.
Haskell's lambda expressions (i.e. anonymous functions) come in this form:
\x -> f x
where x is an argument, and f x an expression using this argument. The special variable _ matches anything and treats it as unimportant.
The "slash" is part of a lambda function, the underscore is a "wildcard" used in patterns (it is discarded). The arrow is another part of the lambda function. The function \ _ -> name returns the name, regardless of input, so the "!" does nothing but provide (unused) input to the function.
I have a question I am rather unsure about.
My questions is as follows
let myFunc (text:string) (times:int) = ....
What I want this function to do is put the string together as many times as specified by the times parameter.
if input = "check " 3 I want the output string = "check check check"
I have tried with a loop, but couldn't seem to make it work.
Anyone?
Actually the function is already in String module:
let multiply text times = String.replicate times text
To write your own function, an efficient way is using StringBuilder:
open System.Text
let multiply (text: string) times =
let sb = new StringBuilder()
for i in 1..times do
sb.Append(text) |> ignore
sb.ToString()
If you want to remove trailing whitespaces as in your example, you can use Trim() member in String class to do so.
A variation on pad's solution, given that it's just a fold:
let multiply n (text: string) =
(StringBuilder(), {1..n})
||> Seq.fold(fun b _ -> b.Append(text))
|> sprintf "%O"
If you want a pure functional "do-it-yourself" version for F# learning purposes, then something like the following snippet will do:
let myFunc times text =
let rec grow result doMore =
if doMore > 0 then
grow (result + text) (doMore- 1)
else
result
grow "" times
Here is the test:
> myFunc 3 "test";;
val it : string = "testtesttest"
Otherwise you should follow the pointer about the standard F# library function replicate given in pad's answer.
String.replicate already provides the functionality you're looking for.
If for some reason you want the arguments reversed, you can do it as follows:
(* A general function you should add to your utilities *)
let flip f a b = f b a
let myFunc = flip String.replicate
In a simple recursive fashion:
let rec dupn = function
|s,1 -> s
|s,n -> s ^ dupn(s, n-1)
Theres is a little problem I want to solve with Haskell:
let substitute a function that change all of the wildcards in a string for one concrete parameter. The function has de signature of:
subs :: String -> String -> String -> String
-- example:
-- subs 'x' "x^3 + x + sin(x)" "6.2" will generate
-- "6.2^3 + 6.2 + sin(6.2)"
You could use the Text.Regex package.
Your example might look something like this:
import Text.Regex(mkRegex, subRegex)
subs :: String -> String -> String -> String
subs wildcard input value = subRegex (mkRegex wildcard) input value
See http://bluebones.net/2007/01/replace-in-haskell/ for an example which looks exactly as the piece of code you are looking for.
You can use text-format-simple library for such cases:
import Text.Format
format "{0}^3 + {0} + sin({0})" ["6.2"]
Use regular expressions (Text.Regex.Posix) and search-replace for /\Wx\W/ (Perl notation). Simply replacing x to 6.2 will bring you trouble with x + quux.
Haskell Regex Replace for more information (I think this should be imported to SO.
For extra hard-core you could parse your expression as AST and do the replacement on that level.