Why does a carriage return character not appear in a F# string literal bound like this
let hw = #"hello
world";;
whereas in C# the following string does contain a carriage return character?
var s2 = #"hello
world";
Thanks
In fact, it is quite easy to spot that the behavior of F# and C# compilers do not differ: being run thru FSC the following
[<EntryPoint>]
let main argv =
let s = #"Hello
world"
printfn "%i" s.Length
0
outputs 12 similarly to equivalent C# code.
What differs is, in fact, the treatment of multi-line string literals by FSI: sending lines 3-5 of the above snippet from VS to FSI with Alt+Enter produces output 11, one less for absence of carriage return within the parsed string literal.
Came out this is a known problem, although I didn't manage to google the rationale behind this behavior.
I ran your code from the fsi and it entered the newline.
let hw = #"hello
world";;
printf "%s" hw;;
output
hello
world
Related
I've got a haskell file:
main = putStrLn "hello world"
let a=1
show a
and ghc says:
main.hs:3:1:
parse error (possibly incorrect indentation or mismatched brackets)
There are a number of problems here.
First, if you want to sequence expressions in IO you need to place them in a do block. Second, you need to use indentation (spaces only, no tabs!) to delimit the do block, like so:
main = do
putStrLn "hello world"
let a=1
show a
Finally, show a will return a string, but you want an IO action that prints a string, so it should be putStrLn (show a), or you can use print a as the print function is the composition of showing (turning into a string) and then printing out to the console.
I am having difficulties escaping '\' in sprintf statements when working with atom editor on Linux with mono.
On Windows with VS:
sprintf "%s" "\\"
is evaluated to
val it : string = "\"
as it should.
If I evaluate the same expression with VSCode or atom-editor under Linux I get
val it : string = "\\"
Further Remark:
If on Windows (I installed Mono on Windows to check this out) I start 'fsharpi' from the 'Mono Command Prompt' the said expression is evaluated correctly as "\". As it does when I do the same thing under Linux.
This looks more like an editor display issue than like a bug in the evaluation itself. To be fair, this always confuses me - should the editor display the string value as it is, or should it display it as a valid escaped F# string? I think both would make sense...
The easiest way to check what value you're really getting is to run a few checks in F# Interactive:
> let s = "\\";;
val s : string = "\"
> s.Length;;
val it : int = 1
> s.[0] = '\\';;
val it : bool = true
I am currently trying to read a file as this:
53**7****\n6**195***\n*98****6*\n8***6***3\n4**8*3**1\n7***2***6\n*6****28*\n***419**5\n****8**79\n
And write it into the screen, but with new lines instead of the /n.
On the msdn description of the method StreamReader.ReadLine () it says that:
A line is defined as a sequence of characters followed by a line feed ("\n"), a carriage return ("\r"), or a carriage return immediately followed by a line feed ("\r\n"). The string that is returned does not contain the terminating carriage return or line feed. The returned value is null if the end of the input stream is reached.
Why does my program not interpret \n as a new line?
Well, the problem is that the documentation for ReadLine is talking about the '\n' (single) character, while you actually have a "\\n" two-character string.
In C#, \ is used as an escape character - for example, \n represents the character with ASCII value of 10. However, files are not parsed according to C# rules (that's a good thing!). Since your file doesn't have the literal 10-characters, they aren't interpreted as endlines, and rightly so - the literal translation in ASCII would be (92, 110).
Just use Split (or Replace), and you'll be fine. Basically, you want to replace "\\n" with "\n" (or better, Environment.NewLine).
I used #Mark Seemann's method by letting let s = inputStream.ReadToEnd () and thereby importing the string you are typing in directly. I am able to print out the same output as you with your do-while loop, but i have to use this recursive printFile method:
let rec printFile (reader : System.IO.StreamReader) =
if not(reader.EndOfStream) then
let line = reader.ReadLine ()
printfn "%s" line
printFile reader
This however does not recognize the \n as new lines - do you know why as i see the methods as very similar? Thanks!
I can't reproduce the issue. This seems to work fine:
let s = "53**7****\n6**195***\n*98****6*\n8***6***3\n4**8*3**1\n7***2***6\n*6****28*\n***419**5\n****8**79\n"
open System.IO
let strm = new MemoryStream()
let sw = new StreamWriter(strm)
sw.Write s
sw.Flush ()
strm.Position <- 0L
let sr = new StreamReader(strm)
while (not sr.EndOfStream) do
let line = sr.ReadLine ()
printfn "%s" line
This prints
53**7****
6**195***
*98****6*
8***6***3
4**8*3**1
7***2***6
*6****28*
***419**5
****8**79
I'm trying to implement a very simple markup language. I have an intermediate representation that looks like:
data Token = Str Text
| Explode Text
type Rep = [Token]
So, the idea is to turn an arbitrary text of the form:
The quick brown %%fox%% %%jumps%% over the %%lazy%% dog.
into:
[Str "The quick brown", Explode "fox", Explode "jumps", Str "over the", Explode "lazy", Str "dog"]
for further processing. Also, it is important that we treat:
%%fox%% %%jumps%%
differently than
%%fox jumps%%
The latter should (Explode "fox jumps")
I tried to implement this using attoparsec, but I don't think I have the tools I need. But I'm not so good with parsing theory (I studied math, not CS). What kind of grammar is this? What kind of parser combinator library should I use? I considered using Parsec with a stateful monad transformer stack to keep track of the context. Does that sound sensible?
You can take the cheap and easy way, without a proper parser. The important thing to recognise is that this grammar is actually fairly simple – it has no recursion or such. It is just a flat listing of Strs and Explodes.
The easy way
So we can start by breaking the string down into a list containing the text and the separators as separate values. We need a data type to separate the separators (%%) from actual text (everything else.)
data ParserTokens = Sep | T Text
Breaking it down
Then we need to break the list into its constituents.
tokenise = intersperse Sep . map T . Text.splitOn "%%"
This will first split the string on %%, so in your example it'll become
["The quick brown ","fox"," ","jumps"," over the ","lazy"," dog."]
then we map T over it, to turn it from a [Text] to a [ParserTokens]. Finally, we intersperse Sep over it, to reintroduce the %% separators but in a shape that's easier to deal with. The result is, in your example,
[T "The quick brown ",Sep,T "fox",Sep,T " ",Sep,T "jumps",Sep,T " over the ",Sep,T "lazy",Sep,T " dog."]
Building it up
With this done, all that remains is parsing this thing into the shape you want it. Parsing this amounts to finding the 1-2-3 punch of Sep–T "something"–Sep and replacing it with Explode "something". We write a recursive function to do this.
construct [] = []
construct (T s : rest) = Str s : construct rest
construct (Sep : T s : Sep : rest) = Explode s : construct rest
construct _ = error "Mismatched '%%'!"
This converts T s to Str s and the combination of separators and a T s into an Explode s. If the pattern matching fails, it's because there were a stray separator somewhere, so I've just set it to crash the program. You might want better error handling there – such as wrapping the result in Either String or something similar.
With this done, we can create the function
parseTemplate = construct . tokenise
and in the end, if we run your example through parseTemplate, we get the expected result
[Str "The quick brown ",Explode "fox",Str " ",Explode "jumps",Str " over the ",Explode "lazy",Str " dog."]
For such simple parser even Attoparsec seems to be overkill:
parse = map (\w -> case w of
'%':'%':expl -> Explode $ init $ init expl
str -> Str str) . words
Of course, this code needs some sanity checks for Explode case.
This doesn't handle whitespace the way you specified, but it should get you on the right track.
parseMU = zipWith ($) (cycle [Str,Explode]) . splitps where
splitps :: String -> [String]
splitps [] = [[]]
splitps ('%':'%':r) = [] : splitps r
splitps (c:r) = let
(a:r') = splitps r
in ((c:a):r')
I am writing my first F# library
I am trying to use string.Format and it complains that no such function exists.
Is it not available or am I doing something wrong?
If you want to avoid using the full name, you can use open in F#:
open System
let s = String.Format("Hello {0}", "world")
This should work in both F# interactive (enter the open clause first) and in normal compiled applications. The key thing is that you must write String with upper-case S. This is because string in C# isn't a usual type name - it is a keyword refering to the System.String type.
Alternatively, you could also take a look at the sprintf function. It is an F#-specific alternative to String.Format which has some nice benefits - for example it is type checked:
let s = sprintf "Hello %s! Number is %d" "world" 42
The compiler will check that the parameters (string and int) match the format specifiers (%s for string and %d for integers). The function also works better in scenarios where you want to use partial function application:
let nums = [ 1 .. 10 ]
let formatted = nums |> List.map (sprintf "number %d")
This will produce a list of strings containing "number 1", "number 2" etc... If you wanted to do this using String.Format, you'd have to explicitly write a lambda function.
the full name of it is:
System.String.Format