How to interpolate a string in Haskell? [closed] - haskell

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a bunch of strings stored in a config file. The strings contain values that must be evaluated at runtime:
"aaa #{val1} bbb"
"ccc #{val235} ddd"
How can I replace the #{valN} at runtime using the standard, out of the box, Haskell library? Do string interpolations, that is.
I can change the format of parts that have to be interpolated, if Haskell requires so. Namely, instead of #{valN} I could use ${valN} or anything else.

As far as I know, there are three ways to do what you want:
1. (++) operator
Since String is just a list of Char, so you can use (++) operator to combine many strings:
> "aaa " ++ show (val1) ++ " bbb"
> "ccc " ++ show (val235) ++ " ddd"
2. printf
printf can really return String type:
λ> printf "Hi, %s!" "Bob" :: String
"Hi, Bob!"
λ> :t it
it :: String
So all you need to do is giving a explicit type signature to your function which you need to return String.
3. string-interpolate package
The following is the sample code from the package document
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
import Data.Text
import Data.String.Interpolate ( i )
λ> age = 33 :: Int
λ> name = "Tatiana" :: Text
λ> [i|{"name": "#{name}", "age": #{age}}|] :: String
>>> "{\"name\": \"Tatiana\", \"age\": 33}"
λ> [i|
Name: #{name}
Age: #{age}
|] :: String
>>> "\nName: Tatiana\nAge: 33\n"
Of course, there are some other interpolation libraries, which are also listed in the package pages.

An option not mentioned in the comments or in Z-Y.L's answer is typelits-printf:
ghci> putStrLn $ printf #"You have %.2f dollars, %s" 3.62 "Luigi"
You have 3.62 dollars, Luigi
See more examples on https://github.com/mstksg/typelits-printf

Related

String Formatting columns in Haskell without Text.Printf

I am new to Haskell. I am at the last part of a school project. I have to take tuples and print them to an outfile and separate them by a tab column. So (709,4226408), (12965,4226412) and (5,4226016) should have and output of
709 4226408
12965 4226412
5 4226016
What I have been trying to do is this:
genOutput :: (Int, Int) -> String
genOutput (a,b) = (show a) ++ "\t" ++ (show b)
And this gives outputs like:
"709\t4226408"
"12965\t4226412"
"5\t4226016"
There are 3 things wrong with this. 1) Quotes still appear in the output. 2) The \t tab does not actually become a tab space. .Whenever I try to make an actual tab for the "" it just comes out as a " " space. 3) They are not aligned into columns like the above example. I know Text.Printf exists but we are not allowed to import anything other than:
import System.IO
import Data.List
import System.Environment
that's the output you get from GHCi I guess? Try to use putStrLn instead:
Prelude> genOutput (1,42)
"1\t42"
Prelude> putStrLn $ genOutput (1,42)
1 42
Why is that?
If you tell GHCi to evaluate an expression it will do so and (more or less) output it using show - show is designed to work with read and will usually output a value as if you would input it directly into Haskell. For a String that will include escape sequences and the "s
Now using putStrLn it will take the string and print it to stdout as you would expect.
Using print
Another reason could be that you use print to output your value - print is show + putStrLn so it'll show the values first re-introducing the escapes (as GHCi would) - so if you use print change it to putStrLn if you are using Strings

How to implement a placeholder in a string haskell

How can I create a function that would print sentences that have placeholders/variables in the missing spaces and then take user input and print a complete sentence by inserting the values into the placeholders.
I'm trying to print multiple sentences(statements) with missing words which then give the user the option to select 4 choices of various words to complete the sentence. The goal is to have variables added within the missing spaces that acts as placeholders which will then take the user input, and store the value into the variables where words are missing to then print a complete sentence. I have explained this further in the "What I have in mind section"
Eg. This sentence ____ not _____.
Options:
1. Is, complete
2. is, finished
3. etc
4. etc
What I have in mind
I'm trying to achieve something along the lines of using a placeholder for those spaces with no text where I can then assign values in said placeholder after the user selects the choice.
someFunction that prints sentence
"This sentence is $a not $b."
Where $a and $b and variables/placeholders that I can call later to
store the words that the user selects.
someFunction that takes the sentence from the first function and takes the options that are printed from another function, and place the value into the placeholders to make the sentence complete.
What I did
My implementation is done in a way that is just rewriting the entire sentence with each possible option that the user can choose, and then printing the sentence that matches the option that the user chooses. This doesn't give me the functional approach that I am looking for, since it's more or a hard coded approach which can get tedious when using multiple sentences which will then have the 4 options for each sentence.
My Code
--First Version
import Data.List
import System.IO
main :: IO()
sentences = do
putStrLn "The Cat is ______ from ______ the city \n"
putStrLn "Here are your options:"
putStrLn "A. big, nearby"
putStrLn "B. Nearby, in"
putStrLn "C: You, By"
putStrLn "D: By, Yourself"
option <- getChar
if (option == 'A' || option == 'a')
then putStrLn "The Cat is big from nearby the city"
else if (option == 'B' || option == 'b')
then putStrLn "The Cat is nearby from in the city"
else putStrLn "Error"
main = sentences
I like using string-interpolate for this because it's exception-safe. Then you can use Maybe's fold maybe to replace your if:
{-# LANGUAGE QuasiQuotes #-}
module Main where
import Control.Monad (forM_)
import Data.Char (toUpper)
import Data.List (lookup)
import Data.Maybe (maybe)
import Data.String.Interpolate ( i )
import System.IO
sentence :: (String, String) -> String
sentence (word1, word2) = [i|The Cat is #{word1} from #{word2} the city \n|]
type Choice = (Char, (String, String))
choices :: [Choice]
choices = [ ('A', ("big" , "nearby"))
, ('B', ("Nearby", "in"))
, ('C', ("You" , "By"))
, ('D', ("By" , "Yourself"))
]
presentChoice :: Choice -> IO ()
presentChoice (option, (word1, word2)) =
putStrLn [i|#{option}. #{word1}, #{word2}|]
sentences = do
putStrLn $ sentence ("______", "______")
putStrLn "Here are your options:"
forM_ choices presentChoice
option <- fmap toUpper getChar
putStrLn $ maybe "Error" sentence $ lookup option choices
main :: IO()
main = sentences

Haskell String formattation as in C

Is it possible to manipulate strings to output just as it is possible in C, I mean:
printf("%.2f", number);
is it possible to do the same formating in Haskell?
You can use the Text.Printf module, which is part of the base package, so it is (normally) already installed. This module is documented as:
A C printf(3)-like formatter. This version has been extended by Bart Massey as per the recommendations of John Meacham and Simon Marlow.
We can make use of the printf function, for example:
Prelude> import Text.Printf
Prelude Text.Printf> number = 3.1415926
Prelude Text.Printf> printf "%.2f\n" number
3.14

Haskell : Check for an exact substring [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to write a function which will check for an EXACT substring in the given string.
All I am using right now is isInfixOf but my friend just pointed out that it doesn't check for an EXACT word.
Example, if I am writing
`"hi " `isInfixOf` "hi you"`
then this will return True. But I don't want that. All I want is it should return True only if it contains "hi " i.e. exactly one space. How can I do that?
It seems like you are looking for a somewhat modified version of isInfixOf:
import Data.Maybe
import Data.List
isInfixOf' :: String -> String -> Bool
isInfixOf' xs ys = any p [stripPrefix xs zs | zs <- tails ys]
where
p Nothing = False
p (Just (' ' : _)) = False
p _ = True
The idea is that we first collect all strings that follow a matching substring and then test whether or not they start with a space.
For example:
> "hi " `isInfixOf'` "hi you"
False
> "hi " `isInfixOf'` "hi you"
True

word count utility in Haskell [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm fairly new to Haskell. I've been trying to create a utility to count the number of words and lines in Haskell for a few days to help me understand the language better. However, I'm struggling to get it working.
So far, I have:
wordCountUtility = do
putStrLn "Please enter the filename:"
filename <- getLine
putStrLn ("The file name you have entered is: " ++ filename)
contents <- readFile filename -- read the file specified in “name” into “contents”
lower <- (return . map toLower) contents
putStrLn lower
I have tried to use 'chop' and found print . length . words =<< getContents and have modified it a number of times, but I have had no luck.
I've also had a look at quite a few similar answers on Stack Overflow, such as : identifying number of words in a paragraph using haskell
The output should be somewhat similar to this:
Amount of Lines within the file
Lines : 10
Amount of Words found within the file
Words : 110
Any help would be much appreciated.
Your wordCountUtility should probably be not be counting words yet. You should just stop at something like
commandLineUtility :: (String -> String) -> IO ()
commandLineUtility fn = do
putStrLn "Please enter the filename:"
filename <- getLine
putStrLn ("The file name you have entered is: " ++ filename)
contents <- readFile filename -- read the file specified in “name” into “contents”
lower <- (return . fn) contents
putStrLn lower
(I am keeping this as close to your text as possible.) Now, though, you have to figure out what
(String -> String) function you want to apply. This is a pure function and should be developed separately. So you might write:
cwlcount :: String -> (Int, Int, Int)
cwlcount str = (length str, length (words str), length (lines str))
format :: (Int, Int, Int) -> String
format (c,w,l) = unlines $
["Number of characters:"
, show c
, "Number of words:"
, show w
, "Number of lines:"
, show l
]
So (format . cwlcount) :: String -> String and you can write:
main :: IO ()
main = commandLineUtility (format . cwlcount)
Of course there are a million objections to this program, but you can improve it by investigating the parts piecemeal. For one thing, it is irritating that the whole list of characters is brought into memory and three length calculations are made for it separately. The Predude.getLine is not very user friendly either...
At the moment, then, our results look so:
$ ghci Sonia_CS.hs
GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main ( Sonia_CS.hs, interpreted )
Ok, modules loaded: Main.
>>> main
Please enter the filename:
Sonia_CS.hs
The file name you have entered is: Sonia_CS.hs
Number of characters:
816
Number of words:
110
Number of lines:
25
Or better:
$ ghc -O2 Sonia_CS.hs
[1 of 1] Compiling Main ( Sonia_CS.hs, Sonia_CS.o )
Linking Sonia_CS ...
$ ./Sonia_CS
Please enter the filename:
/usr/share/dict/words
The file name you have entered is: /usr/share/dict/words
Number of characters:
2493109
Number of words:
235886
Number of lines:
235886

Resources