How do GADT data constructor arguments work in Idris? - implicit

Here is a GADT with three data constructors defining a view for lists:
data SplitList : List a -> Type where
SplitNil : SplitList []
SplitOne : SplitList [x]
SplitPair : (lefts : List a) -> (rights : List a) ->
SplitList (lefts ++ rights)
I don't understand SplitOne: where does the [x] come from? In SplitNil, it seems to just be a constant value (Nil) which is fed to SplitList, but in SplitOne is the x an implicit argument somehow?

I am not an expert, but since nobody else is answering: Yes, and so is the a in the first line: List a -> Type is short for {a : Type} -> List a -> Type.
By type inference, x must have type a, so [x] : List a and SplitList [x] : Type.
What I am not sure about is whether
this a is another implicit argument, so that the full type signature is SplitOne : {a : Type} -> {x : a} -> SplitList [x] (and if so, is its name really a?), or
it's somehow bound by the a from the first line.
But the first makes more sense to me.

Related

How to apply show to any type in haskell?

i am trying to write a function to print all elements of any type in a list (including my own data type), but i find that not all types are an instance of show. is there anyway that can make haskell know that type a is/is not an instance of show? or i can simple turn every type into string. here is my code.
displayList :: [a] -> IO()
displayList (x : xs)
| not (null xs) = (show x) ++ displayList xs
| otherwise = show x ++ show xs
You can indicate in your type signature that the type must be an instance of Show.
displayList :: Show a => [a] -> IO ()
Your recursion looks a bit off though. I would start off with this skeleton:
displayList [] = _base
displayList (x : xs) = _rec
You shouldn't need any guards, and you shouldn't need to use null.
Note: showing lists certain ways requires two base cases:
displayList [] = _base0
displayList [x] = _base1
displayList (x : xs) = _rec
Based on your code so far, I don't think you need that here, but since you didn't show an example of what you want, it's hard to say for sure.

Haskell: Transposition on a list of strings

New to Haskell and the language has been fun so far. I am hoping for a good hint rather than an answer as I am enjoying the mind-altering that is Haskell.
Question: I have a list of strings and I would like to transpose them.
let x = ["hello", "world"]
would become
["hw", "eo", "lr", "ll", "od"]
What I have so far is this:
transposeString :: [a] -> [a]
transposeString ([]:_) = []
transposeString x = (map head x) : transposeString (map tail x)
I definitely know there is something wrong with the type signature. My rational is that
Let y = ["wow", "top"]
map head y
returns "wt" so recursing this on the rest of the list would work?
Thank you in advance for any hints.
Mind that you do not have to provide a type signature: the Haskell compiler can derive one. If you put your implementation in a file:
transposeString ([]:_) = []
transposeString x = (map head x) : transposeString (map tail x)
and query the type with :t in ghci, it returns:
*Main> :t transposeString
transposeString :: [[b]] -> [[b]]
This makes perfect sense:
you transpose a matrix, which is a list of lists. [[b]] is a list of lists of b elements; and
you can derive it from the implementation yourself: map head x means that elements of x must be a list ([b]) since we perform a mapping, we have to nest the list one additional level so [[b]]. The same for tail.
As far as I know, your implementation is correctly. You can specialize it by saying that [b] ~ String, thus adding a type signature for Strings:
transposeString :: [String] -> [String]
transposeString ([]:_) = []
transposeString x = (map head x) : transposeString (map tail x)
which again makes sense because String ~ [Char] thus b ~ Char. But there is not much point in specializing a functions type: you better always use the most generic type signature. In this case [[b]] -> [[b]].
One point of note. Your type signature for tranposeString allows to accept a flat list as an argument. Tranposing a [String] works because [String]s are really just [[Char]]s, but what happens when you try to call transposeString on an [Int]? After all, the type signature allows for it.
On a side note, I ask you, given your current function, what would happen if your called transposeString []?
Do remember String is [Char]
"abc" == 'a' : 'b' : 'c' : []
From here you can use traversable nature of lists:
transpose :: [[a]] -> [[a]]
transpose mat = getZipList $ sequenceA $ map ZipList mat
test' = transpose [[1,2,3],[4,5,6],[7,8,9]] -- == [[1,4,7],[2,5,8],[3,6,9]]
test'' = transpose ["abc", "deg", "klm"] -- == ["adk","bel","cgm"]
You can also check default implementation of transponse in haskell doc
https://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#transpose
transpose :: [[a]] -> [[a]]
transpose [] = []
transpose ([] : xss) = transpose xss
transpose ((x:xs) : xss) = (x : [h | (h:_) <- xss]) : transpose (xs : [ t | (_:t) <- xss])

Why can't I pattern match on the concatenation function (++) in Haskell?

I'm trying to match **String Newline String** pattern in a function Split.
split::String -> [String]
split[] = []
split (x++'\n':xs) = [x]++split(xs)
I'm getting this error:
Parse error in pattern: x ++ ('\n' : xs)
What am I doing wrong here?
I know there are other ways of achieving the same result but I'd like to understand what wrong with this pattern. I'm fairly new to Haskell BTW.
One problem (as I understand it) is that ++ is not a constructor of the list data type the way : is. You can think of the list data type being defined as
data [a] = [] | a : [a]
Where : is a constructor that appends elements to the front of a list. However, ++ is a function (defined in the documentation here: http://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#%2B%2B) as
(++) :: [a] -> [a] -> [a]
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
We could define our own data type list like
data List a = Empty | Cons a (List a)
That would mimic the behavior of our familiar list. In fact, you could use (Cons val) in a pattern. I believe you could also define a type with a concat constructor like so
data CList a = Empty | Cons a (CList a) | Concat (CList a) (CList a)
Which you could use to lazily concatenate two lists and defer joining them into one. With such a data type you could pattern match against the Concat xs ys input, but you that would only work on the boundary of two lists and not in the middle of one.
Anyway I'm still fairly new to Haskell myself but I hope this is on point.
Imagine you could. Then matching "a\nb\nc" could produce x = "a", xs = "b\nc" or x = "a\nb", xs = "c" and you'd need some ad hoc rule to decide which to use. Matching against functions is also impossible to reasonably implement in general: you need to find an x given f x, and there is no way to do this other than trying all possible x.

Haskell error with a replicate-like function

I want to write a replicate-like function that works like this :
repli "the" 3 = "ttthhheee" and
repli "jason" 4 = "jjjjaaaassssoooonnnn"
Here is the code that I wrote :
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n)
The error I get is this :
Couldn't match expected type `[a]' against inferred type `Char'
Expected type: [[a]]
Inferred type: [Char]
In the first argument of `repli', namely `"jason"'
In the expression: repli "jason" 3
How can I fix this? Thanks.
For problems with types, here's a trick that has helped me immensely. Whenever I am completely baffled by a message like this, I do the following:
If there's a type signature on the function in question, remove it and see if anything changes. If it compiles, ask ghci what the type is (using :t). If it doesn't compile, at least the error message may differ enough to give you another clue.
If there's no type signature, add one. Even if it doesn't compile, the error message may give you another clue.
If that doesn't help, then temporarily add type declarations on each of the expressions in the function. (Often you'll need to break up some of the expressions to see what's really going on. You may also need to temporarily enable the ScopedTypeVariables pragma.) Compile again and check the error messages.
That last one is more work, but I've learned a lot from that exercise. It usually pinpoints the exact place where there's a mismatch between what I think the type is and what GHC thinks the type is.
So let's begin by adding type signatures to your code:
myrepli :: [a] -> Int -> [a]
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli :: [a] -> Int -> [a]
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n) -- triggers a compiler error
Ah, now we get a compiler error:
amy.hs:9:27:
Couldn't match expected type `a' with actual type `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Int -> [a] at amy.hs:7:10
In the first argument of `myrepli', namely `x'
In the first argument of `(++)', namely `(myrepli x n)'
In the expression: (myrepli x n) ++ (repli xs n)
The problem is in the call to myrepli x n. The function myrepli expects a list/string, but you're passing it a single character. Change that last line to:
repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)
At that point you will find other errors in your code. But rather than fix your code, let me show you another way to do it:
repl (x:xs) n = (myReplicate x n) ++ (repl xs n)
repl [] _ = []
-- You could use the library function "replicate" here, but as a
-- learning exercise, we'll write our own.
myReplicate a n = take n (repeat a)
myrepli is expecting a list and an integer. However, the definition of repli calls it with x, which is an item, not a list of items.
I imagine you either want to change myrepli to take a single item as argument, or you want to change repli to pass [x] instead of just x. (I would suggest the former rather than the latter.)

Inferred type appears to detect an infinite loop, but what's really happening?

In Andrew Koenig’s An anecdote about ML type inference, the author uses implementation of merge sort as a learning exercise for ML and is pleased to find an “incorrect” type inference.
Much to my surprise, the compiler reported a type of
'a list -> int list
In other words, this sort function accepts a list of any type at all and returns a list of integers.
That is impossible. The output must be a permutation of the input; how can it possibly have a different type? The reader will surely find my first impulse familiar: I wondered if I had uncovered a bug in the compiler!
After thinking about it some more, I realized that there was another way in which the function could ignore its argument: perhaps it sometimes didn't return at all. Indeed, when I tried it, that is exactly what happened: sort(nil) did return nil, but sorting any non-empty list would go into an infinite recursion loop.
When translated to Haskell
split [] = ([], [])
split [x] = ([x], [])
split (x:y:xs) = (x:s1, y:s2)
where (s1,s2) = split xs
merge xs [] = xs
merge [] ys = ys
merge xx#(x:xs) yy#(y:ys)
| x < y = x : merge xs yy
| otherwise = y : merge xx ys
mergesort [] = []
mergesort xs = merge (mergesort p) (mergesort q)
where (p,q) = split xs
GHC infers a similar type:
*Main> :t mergesort
mergesort :: (Ord a) => [t] -> [a]
How does the Damas–Hindley–Milner algorithm infer this type?
This is indeed a remarkable example; an infinite loop being detected, essentially, at compile time! There is nothing special about the Hindley–Milner inference in this example; it just proceeds as usual.
Note that ghc gets the types of split and merge correctly:
*Main> :t split
split :: [a] -> ([a], [a])
*Main> :t merge
merge :: (Ord t) => [t] -> [t] -> [t]
Now when it comes to mergesort, it is, in general, a function t1→t2 for some types t1 and t2. Then it sees the first line:
mergesort [] = []
and realizes that t1 and t2 must be list types, say t1=[t3] and t2=[t4]. So mergesort must be a function [t3]→[t4]. The next line
mergesort xs = merge (mergesort p) (mergesort q)
where (p,q) = split xs
tells it that:
xs must be an input to split, i.e., of type [a] for some a (which it already is, for a=t3).
So p and q are also of type [t3], since split is [a]→([a],[a])
mergesort p, therefore, (recall that mergesort is believed to be of type [t3]→[t4]) is of type [t4].
mergesort q is of type [t4] for exactly the same reason.
As merge has type (Ord t) => [t] -> [t] -> [t], and the inputs in the expression merge (mergesort p) (mergesort q) are both of type [t4], the type t4 must be in Ord.
Finally, the type of merge (mergesort p) (mergesort q) is the same as both its inputs, namely [t4]. This fits with the previously known type [t3]→[t4] for mergesort, so there are no more inferences to be done and the "unification" part of the Hindley–Milner algorithm is complete. mergesort is of type [t3]→[t4] with t4 in Ord.
That's why you get:
*Main> :t mergesort
mergesort :: (Ord a) => [t] -> [a]
(The description above in terms of logical inference is equivalent to what the algorithm does, but the specific sequence of steps the algorithm follows is simply that given on the Wikipedia page, for example.)
That type can be inferred because it sees that you pass the result of mergesort to merge, which in turn compares the heads of the lists with <, which is part of the Ord typeclass. So the type inference can reason that it must return a list of an instance of Ord. Of course, since it actually recurses infinitely, we can't infer anything else about the type it doesn't actually return.

Resources