Syntax rules for Haskell infix datatype constructors - haskell

I'm trying to make a Haskell datatype a bit like a python dictionary, a ruby hash or a javascript object, in which a string is linked to a value, like so:
data Entry t = Entry String t
type Dictionary t = [Entry t]
The above code works fine. However, I would like a slightly nicer constructor, so I tried defining it like this:
data Entry t = String ~> t
This failed. I tried this:
data Entry t = [Char] ~> t
Again, it failed. I know that ~ has special meaning in Haskell, and GHCi still permits the operator ~>, but I still tried one other way:
data Entry t = [Char] & t
And yet another failure due to parse error. I find this confusing because, for some inexplicable reason, this works:
data Entry t = String :> t
Does this mean that there are certain rules for what characters may occur in infix type constructors, or is it a cast of misinterpretation. I'm not a newbie in Haskell, and I'm aware that it would be more idiomatic to use the first constructor, but this one's stumping me, and it seems to be an important part of Haskell that I'm missing.

Any operator that starts with a colon : is a type constructor or a data constructor, with the exception of (->). If you want the tilde, you could use :~>, but you're not going to get away with using something that doesn't start with a colon. Source

Related

Why does the Maybe return type make this crash?

I'm restricting myself the use of prebuilt-in functions for training purposes. I have recoded length as count and it works.
I have a search funtion that simply returns a value at index in a list when given an index and a list. It works completly fine. It throws an error when the index is too large.
search [] _ = error "index too large"
search (a:_) 0 = a
search (_:a) b = search a (b - 1)
Now, I want a safeSearch function that return Nothing if the index is too large of if the list is empty. So I've simply done this.
safeSearch :: [a] -> Int -> Maybe a
safeSearch a b
| b < 0 || b >= count a = Nothing
| otherwise = Just (search a b)
And it works! ... as long as you don't try it on an empty list. Even with an index too large for the list length.
main = print(safeSearch [] 5)
This crashes and I really can't find any way around it.
Even though I don't think my second line is usefull (because if the list is empty, its count is 0 so we drop in the first guard and it should return Nothing?) its not working. Removing it does not solve the problem.
Here's the compile-time error.
main.hs:91:8: error:
* Ambiguous type variable `a0' arising from a use of `print'
prevents the constraint `(Show a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Show Ordering -- Defined in `GHC.Show'
instance Show Integer -- Defined in `GHC.Show'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
...plus 22 others
...plus 13 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In the expression: print (safeSearch [] 5)
In an equation for `main': main = print (safeSearch [] 5)
|
91 | main = print(safeSearch [] 5)
| ^^^^^^^^^^^^^^^^^^^^^^
exit status 1
Any idea? Something I'm missing or even completly going wrong? A concept I need to understand deeper?
The problem is a compile error. That means it isn't actually running your code and hitting your error "index too large" call; the compiler is rejecting your code before it can even try to run it. So you're looking in the wrong place if you're trying to change the code to avoid that.
What's actually happening is that safeSearch [] 5 is returning a value of type Maybe a, where a is the type of the elements in the list. But you didn't include any elements in the list, so there is nothing at all to decide what that type a is.
Your function safeSearch can work for any type, so that's actually fine. But you also try to print the Maybe a value. Using print requires a Show instance, and the instance for Maybe a requires there to also be a Show instance for a. Because there is nothing saying what type a is, the compiler has no way of finding the appropriate Show instance for it, so it has to abort compilation with an error.
The most straightforward way to solve it is to add a type annotation (either of the list, or the Maybe a value resulting from safeSearch). Something like this:
main = print (safeSearch ([] :: [Int]) 5)
(This is what the error message is talking about when it says an ambiguous type variable is preventing a Show constraint from being solved, and that the probable fix is to add a type annotation)
Note that this sort of issue is rarely a problem in "real" code. Normally if you have a list processed into another structure with a related type, you will have other code that does something with the elements or the result, or that produced the list (which isn't always empty). You wouldn't normally write a program that does nothing but process an always-empty list and print the result, except for these kinds of quick tests. So normally, when there is that other code as well, there will be enough context for the compiler to deduce the type of your empty list, and the extra type annotations will not be needed. So this kind of extra type annotation is not usually considered a serious burden that needs to be avoided, because they are hardly ever needed in "real" code. You just code as you want, and on the occassion that a compile error makes your realise you need an annotation you simply add it and move on.
If you do this kind of quick check in GHCi rather than writing a full program with a main function, then you also would not have needed the extra type annotation. This is because GHCi has the ExtendedDefaultRules language extension turned on by default. The "default rules" are conditions when GHC will choose a type for you instead of throwing an "ambiguous type" error. The normal default rules are pretty strict, and really only designed for defaulting numeric constraints (like Num a or Real a, etc). They do not apply to your original example. The "extended default rules" apply more often to avoid needing lots of type signatures in the interactive interpreter (since there you enter one line at a time, instead of the compiler being able to see the full module to infer types from usage). In this case entering print (safeSearch [] 5) at the interpreter prompt will work because it defaults the returned type to Maybe (), and it just so happens that printing Nothing :: Maybe () produces the same output as it would if it had correctly guessed the type you actually meant.
But in almost any real program, defaulting a type variable to () will be a stupid thing to do that makes things work less, so I do not recommend getting into the habit of enabling ExtendedDefaultRules in an actual module. Just add the type annotation, or do quick checks in the interpreter instead of in a module.
What you've written works great for any real-world use case. It only fails when someone writes print (safeSearch [] x) - a literal empty list, with no context to tell what result type is expected. It works fine if they pass in a nonempty list, or a list expression that happens to evaluate to an empty list, or if they use the result in a way that lets type inference figure out what was intended.
Further, there is really no way to write the function so that it works when passed a contextless empty list. The burden to make the types clear is necessarily placed on call sites, not the definition. The comments on your question have already shown how to do this; you only have to be that explicit when you're calling your function in a way that's obviously useless.

What are the rules regarding naming in Haskell?

Are there definite rules regarding naming of entities in Haskell? (by entities I mean functions, term level variables, data constructors, type variables, type constructors, typeclasses, modules; not sure if I left something out here) For example
<interactive>:1:13: error:
Not in scope: type constructor or class ‘Zed’
Perhaps you meant type variable ‘zed’ (line 1)
I know that in type signatures concrete types must be uppercase. So is it assuming that Zed is a concrete type, and because this type isn't defined (isn't in scope), we get an error?
Are there any other actual rules on naming stuff in Haskell?
As was pointed out by M. Aroosi in a comment, your errors don't match your example – you seem to have written f :: zed -> Zed : f = undefined instead, with a : instead of a ;. If you use a ; you will get one of two results. If Zed is undefined, you'll get an error telling you so:
Prelude> f :: zed -> Zed ; f = undefined
<interactive>:2:13: error:
Not in scope: type constructor or class ‘Zed’
Perhaps you meant type variable ‘zed’ (line 2)
If Zed is defined, everything will work:
Prelude> data Zed = TheZed
Prelude> f :: zed -> Zed ; f = undefined
Prelude>
The general rule for Haskell names is:
At the type level:
Type names start with an uppercase letter.
Type variables start with a lowercase letter.
At the term level:
Constructor names start with an uppercase letter if they're ordinary names.
Constructor infix operators start with a :.
Variable names start with a lowercase letter if they're ordinary names.
Variable infix operators start with anything but a :.
There are some further wrinkles (e.g., you can't use , in names; you can't have a name that's only -s and 2 or more character long), but that covers 95% of it.
You are using the REPL (Ghci). If you try to use a type signature in the REPL, you need to use :{ .....\n ..... \n ..... :} kind of multiline input. Then you can do the type signature of the function along with implementation(s) of that type signature. Its not very practical - 1 typo and you have to do it all over again. (Julia language REPL does a much better job with that, btw.).
And yes, there are style guides and types need to start with an uppercase. Usually the compiler warns/errors you.
Since you seem to start out, I suggest you use a source file for your experiments because as soon as you end up with multiple line constructs, the REPL kind of sucks. And it is really easy to use a file for your code. See :load :cd :reload etc. for your GHCI commands which support you doing that.

Convert one full String to ints and words as an interpreter in Haskell

I am trying to write a Forth interpreter in Haskell. There are many sub problems and categories to accomplish this, however, I am trying to accomplish the most basic of steps, and I have been at it for some time in different approaches. The simple input case I am trying to get to is "25 12 +" -> [37]. I am not worried about the lists in Forth are backwards from Haskell, but I do want to try and accommodate the extensibility of the input string down the road, so I am using Maybe, as if there is an error, I will just do Nothing.
I first tried to break the input string into a list of "words" using Prelude's words function. From there I used Prelude's reads function to turn it into a list of tuples (Int,String). So this works great, up until I get to a command "word", such as the char + in the sample problem.
So how do I parse/interpret the string's command to something I can use?
Do I create a new data structure that has all the Forth commands or special characters? (assuming this, how do I convert it from the string format to that data type?)
Need anything else, just ask. I appreciate the help thinking this through.
read is essentially a very simple string parser. Rather than adapting it, you might want to consider learning to use a parser combinator library such as Parsec.
There are a bunch of different tutorials about parser combinators so you'll probably need to do a bit of reading before they 'click.' However, the first example in this tutorial is quite closely related to your problem.
import Text.Parsec
import Text.Parsec.String
play :: String -> Either ParseError Integer
play s = parse pmain "parameter" s
pmain :: Parser Integer
pmain = do
x <- pnum `chainl1` pplus
eof
return x
pnum = read `fmap` many1 digit
pplus = char '+' >> return (+)
It's a simple parser that evaluates arbitrarily long lists:
*Main> play "1+2+3+4+5"
Right 15
It also produces useful parse errors:
*Main> play "1+2+3+4+5~"
Left "parameter" (line 1, column 10):
unexpected '~'
expecting digit, "+" or end of input
If you can understand this simple parser, you should be able to work out how to adapt it to your particular problem (referring to the list of generic combinators in the documentation for Text.Parsec.Combinator). It will take a little longer at first than using read, but using a proper parsing library will make it much easier to achieve the ultimate goal of parsing Forth's whole grammar.

Is it a bad idea to use [Char] instead of String in Haskell function type declaration

I have just started learning Haskell using "Learn you a Haskell for Great Good".
I am currently reading "Types and Typeclasses" chapter, so my knowledge is pretty .. non-existent.
I am using Sublime Text 2 with SublimeHaskell package which builds/checks file on every save.
The problem: I'm trying to make function type declaration like this:
funcName :: [Char] -> [Char]
I'm getting this warning:
Warning: Use String
Found:
[Char] -> [Char]
Why not:
String -> String
Build FAILED
Can you explain to me why is it a bad idea to use Char array instead of String or give me a link to an explanation of possible repercussions etc. I've googled and found nothing.
P.S. I'm a C# developer, I understand the difference between char array and strings in c-like languages.
Somewhere in the base library you will find this definition:
type String = [Char]
which says that String and [Char] are exactly the same thing. Which of the two you choose is a documentation choice. I often define type aliases like this:
type Domain = ByteString
type UserName = Text
It's a good idea to use types for documentation.
Also as an important side note, [Char] is not the type for character arrays, but character lists. Since there are also actual array types, the distinction is important!
String is nothing more than a type alias for [Char], so there is no practical between the two - it's simply a matter of readability.
You seem to be running HLint on your code automatically, and treating any HLint warnings as fatal errors. As the HLint author says "Do not blindly apply the output of HLint". String and [Char] are exactly the same, as everyone says, it's a question of which looks nicer. I would tend to use String if I'm operating on contiguous lists of characters I want to treat as a block (most of the time), and explicitly use [Char] when the characters don't make sense combined in a run (far rarer). HLint divides all hints into error (fix) and warning (think), so perhaps it might be best only to build fail on error hints.

FastCGI Haskell script to make use of Pandoc text conversion

1. Motivation
I'm writing my own mini-wiki. I want to be able to easily convert from markdown to LATEX/HTML and vice versa. After some searching I discovered Pandoc, which is written in Haskell and that I could use the FastCGI module to run a Haskell program on my Apache server.
2. Problem/ Question
I'm not sure how to what protocol I should use to send my FastCGI script the input/output variables (POST/GET?) and how this is done exactly. Any ideas, suggestions, solutions?
3. Steps taken
3.1 Attempt
Here is what I've done so far (based on example code). Note, I have no experience in Haskell and at the moment I don't have too much time to learn the language. I'd just love to be able to use the pandoc text format conversion tool.
module Main ( main ) where
import Control.Concurrent
import Network.FastCGI
import Text.Pandoc
--initialize Variables/ functions
fastcgiResult :: CGI CGIResult
markdownToHTML:: String -> String
--implement conversion function
markdownToHTML s = writeLaTeX defaultWriterOptions {writerReferenceLinks = True} (readMarkdown defaultParserState s)
--main action
fastcgiResult = do
setHeader "Content-type" "text/plain"
n <- queryString
output $ (markdownToHTML n)
main :: IO ()
main = runFastCGIConcurrent' forkIO 10 fastcgiResult
This code reads the string after the question mark in the request url. But this is not a good solution as certain characters are omitted (e.g. '#' ) and spaces are replaced by "/20%".
Thanks in advance.
3.2 Network.CGI
Documentation found here. Under the heading "Input" there are a number of methods to get input. Which one is right for me?
Is it :
Get the value of an input variable, for example from a form. If the variable has multiple values, the first one is returned. Example:
query <- getInput "query"
So lets say I have a HTML POST form with name='Joe' can I grab this using getInput? And if so how do I handle the Maybe String type?
The fastCGI package is actually a extension of the cgi package, which includes the protocol types for receiving request data and returning result pages. I'd suggest using CGI to start with, and then move to fastCGI once you know what you are doing.
You might also want to look at this tutorial.
Edit to answer questions about the tutorial:
"Maybe a" is a type that can either contain "Just a" or "Nothing". Most languages use a null pointer to indicate that there is no data, but Haskell doesn't have null pointers. So we have an explicit "Maybe" type instead for cases when the data might be null. The two constructors ("Just" and "Nothing") along with the type force you to explicitly allow for the null case when it might happen, but also let you ignore it when it can't happen.
The "maybe" function is the universal extractor for Maybe types. The signature is:
maybe :: b -> (a -> b) -> Maybe a -> b
Taking the arguments from front to back, the "Maybe a" third argument is the value you are trying to work with. The second argument is a function called if the third argument is "Just v", in which case the result is "f v". The first argument is the default, returned if the third is "Nothing".
In this case, the trick is that the "cgiMain" function is called twice. If it finds an input field "name" then the "mn" variable will be set to (Just "Joe Bloggs"), otherwise it will be set to (Nothing). (I'm using brackets to delimit values now because quotes are being used for strings).
So the "maybe" call returns the page to render. The first time through no name is provided, so "mn" is (Nothing) and the default "inputForm" page is returned for rendering. When the user clicks Submit the same URL is requested, but this time with the "name" field set, so now you get the "greet" function called with the name as an argument, so it says "Hello Joe Bloggs".

Resources