Is the type of this function well defined - haskell

I'm pretty new to Haskell and I have created a high-order function:
forAll f ls ls2 = all (`f` ls) ls2
I need to specify the type, but I have doubts with the type of the function f:
GHCi says it's:
forAll :: (a -> t -> Bool) -> t -> [a] -> Bool
But shouldn't it be something like this?
forAll :: (a -> t) -> t -> [a] -> Bool
Thanks.

No, since all has the type
all :: (a -> Bool) -> [a] -> Bool
f has to return Bool. Since
(`f` ls)
(\a -> a `f` ls)
flip f ls
f must take an element of the list, ls, and produce a Bool. Making it's type
f :: a -> t -> Bool
Where ls :: t and ls2 :: [a].

Let's examine the type you suspect this function must take.
The type (a -> t) means that given some a we can produce a t. We have some as in our list of as, [a] and so we can presumably make a bunch of ts with a type like [t]. Further, we have yet another t passed in which we can stick in that other bunch of [t]s as well.
Now, I call these as and ts because we really don't know anything about what their actual types are. That said, we do know what our goal is: we must produce a Bool.
So somewhere inside our function must be a method of converting a bunch of ts, like [t], into a Bool. We could do this with something like length ts > 3 but I doubt that's what you're looking for.
The function type that GHC provides you looks a bit different. It states that we have a way of taking an a and a t together to a Bool (the type is (a -> t -> Bool)). Since we have a list of as we can feed each one of them one after another into this function so long as we have a source of ts. Since we have exactly one t coming in, we'll need to use it each time. Altogether that gives us a bunch of Bools, a [Bool] even. This is exactly the kind of thing we're looking for, though, as we'd like to condense that list of [Bool] to a single Bool using all.
This kind of narrative of types I've laid out—where we talk about functions having and wanting values, like a game of give and take between you and your program—is a pretty common method of reasoning about the types of your programs. You can often get quite far with this kind of exploration and provide yourself a lot of justification for the types of programs you've constructed.
Ultimately, GHC is always going to be "right" about the type of the particular values you ask it about—that's the advantage of an Hindley Milner type system. Try to check the types of functions that GHC infers often and see whether GHC has deduced some detail of the type narrative that you've missed.
(By the way, that narrative I mention is called, perhaps obviously, "game semantics of programs" and it also shows up in proofs and logic. There's a much deeper tie there if you decide to follow it.)

Related

Haskell RankNTypes - restriction of function domain

I don't understand why it is so, referring to : What is the purpose of Rank2Types? -> #dfeuer explanation:
... Requiring an argument to be polymorphic doesn't just allow it to be used with multiple types; it also restricts what that function can do with its argument(s) and how it can produce its result
...
f :: (forall a . [a] -> a) -> IO ()
... In fact, no function returning an element not in the list it is given will typecheck
In any explanation of rank-N types I haven't see this effect (or benefit) described, much of the time it was the story about letting the callee choose the type etc... that is clear for me and easy to grasp but I don't see by which virtue (only of extending the rank) we can control/restrict the function domain (and co-domain)...
if somebody could give a deeper insigth of the rankN mechanism involved here. thx
Just think about it in terms of polymorphic functions you declare on the top-level. A function with the signature like
foo :: [Int] -> Int
has lots of possible implementations like
foo = sum
foo = length
foo _ = 39
but none of these are legal if the signature were
foo :: [a] -> a
because then you can't give an integer as the result – you must provide a result of whatever type the caller demands. So the implementation is much more restricted: the result must come from the input list, because that's the only place you know the elements have type a no matter what the caller actually instantiates this to. Only something like
foo = head
will work then.
Your RankN signature requires its argument to be such a polymorphic function, i.e. the argument can't be a [Int] -> Int but only the more restrictive [a] -> a.

Haskell: Typeclass vs passing a function

To me it seems that you can always pass function arguments rather than using a typeclass. For example rather than defining equality typeclass:
class Eq a where
(==) :: a -> a -> Bool
And using it in other functions to indicate type argument must be an instance of Eq:
elem :: (Eq a) => a -> [a] -> Bool
Can't we just define our elem function without using a typeclass and instead pass a function argument that does the job?
Yes. This is called "dictionary passing style". Sometimes when I am doing some especially tricky things, I need to scrap a typeclass and turn it into a dictionary, because dictionary passing is more powerful1, yet often quite cumbersome, making conceptually simple code look quite complicated. I use dictionary passing style sometimes in languages that aren't Haskell to simulate typeclasses (but have learned that that is usually not as great an idea as it sounds).
Of course, whenever there is a difference in expressive power, there is a trade-off. While you can use a given API in more ways if it is written using DPS, the API gets more information if you can't. One way this shows up in practice is in Data.Set, which relies on the fact that there is only one Ord dictionary per type. The Set stores its elements sorted according to Ord, and if you build a set with one dictionary, and then inserted an element using a different one, as would be possible with DPS, you could break Set's invariant and cause it to crash. This uniqueness problem can be mitigated using a phantom existential type to mark the dictionary, but, again, at the cost of quite a bit of annoying complexity in the API. This also shows up in pretty much the same way in the Typeable API.
The uniqueness bit doesn't come up very often. What typeclasses are great at is writing code for you. For example,
catProcs :: (i -> Maybe String) -> (i -> Maybe String) -> (i -> Maybe String)
catProcs f g = f <> g
which takes two "processors" which take an input and might give an output, and concatenates them, flattening away Nothing, would have to be written in DPS something like this:
catProcs f g = (<>) (funcSemi (maybeSemi listSemi)) f g
We essentially had to spell out the type we're using it at again, even though we already spelled it out in the type signature, and even that was redundant because the compiler already knows all the types. Because there's only one way to construct a given Semigroup at a type, the compiler can do it for you. This has a "compound interest" type effect when you start defining a lot of parametric instances and using the structure of your types to compute for you, as in the Data.Functor.* combinators, and this is used to great effect with deriving via where you can essentially get all the "standard" algebraic structure of your type written for you.
And don't even get me started on MPTC's and fundeps, which feed information back into typechecking and inference. I have never tried converting such a thing to DPS -- I suspect it would involve passing around a lot of type equality proofs -- but in any case I'm sure it would be a lot more work for my brain than I would be comfortable with.
--
1Unless you use reflection in which case they become equivalent in power -- but reflection can also be cumbersome to use.
Yes. That (called dictionary passing) is basically what the compiler does to typeclasses anyway. For that function, done literally, it would look a bit like this:
elemBy :: (a -> a -> Bool) -> a -> [a] -> Bool
elemBy _ _ [] = False
elemBy eq x (y:ys) = eq x y || elemBy eq x ys
Calling elemBy (==) x xs is now equivalent to elem x xs. And in this specific case, you can go a step further: eq has the same first argument every time, so you can make it the caller's responsibility to apply that, and end up with this:
elemBy2 :: (a -> Bool) -> [a] -> Bool
elemBy2 _ [] = False
elemBy2 eqx (y:ys) = eqx y || elemBy2 eqx ys
Calling elemBy2 (x ==) xs is now equivalent to elem x xs.
...Oh wait. That's just any. (And in fact, in the standard library, elem = any . (==).)

Can I verify whether a given function type signature has a potential implementation?

In case of explicit type annotations Haskell checks whether the inferred type is at least as polymorphic as its signature, or in other words, whether the inferred type is a subtype of the explicit one. Hence, the following functions are ill-typed:
foo :: a -> b
foo x = x
bar :: (a -> b) -> a -> c
bar f x = f x
In my scenario, however, I only have a function signature and need to verify, whether it is "inhabited" by a potential implementation - hopefully, this explanation makes sense at all!
Due to the parametricity property I'd assume that for both foo and bar there don't exist an implementation and consequently, both should be rejected. But I don't know how to conclude this programmatically.
Goal is to sort out all or at least a subset of invalid type signatures like ones above. I am grateful for every hint.
Goal is to sort out all or at least a subset of invalid type signatures like ones above. I am grateful for every hint.
You might want to have a look at the Curry-Howard correspondence.
Basically, types in functional programs correspond to logical formulas.
Just replace -> with implication, (,) with conjunction (AND), and Either with disjunction (OR). Inhabited types are exactly those having a corresponding formula which is a tautology in intuitionistic logic.
There are algorithms which can decide provability in intuitionistic logic (e.g. exploiting cut-elimination in Gentzen's sequents), but the problem is PSPACE-complete, so in general we can't work with very large types. For medium-sized types, though, the cut-elimination algorithm works fine.
If you only want a subset of not-inhabited types, you can restrict to those having a corresponding formula which is NOT a tautology in classical logic. This is correct, since intuitionistic tautologies are also classical ones. Checking whether a formula P is not a classical tautology can be done by asking whether not P is a satisfiable formula. So, the problem is in NP. Not much, but better than PSPACE-complete.
For instance, both the above-mentioned types
a -> b
(a -> b) -> a -> c
are clearly NOT tautologies! Hence they are not inhabited.
Finally, note that in Haskell undefined :: T and let x = x in x :: T for any type T, so technically every type is inhabited. Once one restricts to terminating programs which are free from runtime errors, we get a more meaningful notion of "inhabited", which is the one addressed by the Curry-Howard correspondence.
Here's a recent implementation of that as a GHC plugin that unfortunately requires GHC HEAD currently.
It consists of a type class with a single method
class JustDoIt a where
justDoIt :: a
Such that justDoIt typechecks whenever the plugin can find an inhabitant of its inferred type.
foo :: (r -> Either e a) -> (a -> (r -> Either e b)) -> (r -> Either e (a,b))
foo = justDoIt
For more information, read Joachim Breitner's blogpost, which also mentions a few other options: djinn (already in other comments here), exference, curryhoward for Scala, hezarfen for Idris.

Example of deep understanding of currying

Reading https://wiki.haskell.org/Currying
it states :
Much of the time, currying can be ignored by the new programmer. The
major advantage of considering all functions as curried is
theoretical: formal proofs are easier when all functions are treated
uniformly (one argument in, one result out). Having said that, there
are Haskell idioms and techniques for which you need to understand
currying.
What is a Haskell technique/idiom that a deeper understanding of currying is required ?
Partial function application isn't really a distinct feature of Haskell; it is just a consequence of curried functions.
map :: (a -> b) -> [a] -> [b]
In a language like Python, map always takes two arguments: a function of type a -> b and a list of type [a]
map(f, [x, y, z]) == [f(x), f(y), f(z)]
This requires you to pretend that the -> syntax is just for show, and that the -> between (a -> b) and [a] is not really the same as the one between [a] -> [b]. However, that is not the case; it's the exact same operator, and it is right-associative. The type of map can be explicitly parenthesized as
map :: (a -> b) -> ([a] -> [b])
and suddenly it seems much less interesting that you might give only one argument (the function) to map and get back a new function of type [a] -> [b]. That is all partial function application is: taking advantage of the fact that all functions are curried.
In fact, you never really give more than one argument to a function. To go along with -> being right-associative, function application is left-associative, meaning a "multi-argument" call like
map f [1,2,3]
is really two function applications, which becomes clearer if we parenthesize it.
(map f) [1,2,3]
map is first "partially" applied to one argument f, which returns a new function. This function is then applied to [1,2,3] to get the final result.

Is there a good reason why `deleteBy` does not have its most general type?

The Haskell 2010 Language Report states in section 20.10.1.1 that:
deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
In fact, the implementation in the GHC library would allow
deleteBy :: (b -> a -> Bool) -> b -> [a] -> [a]
but actually restricts the type to the former one with the annotation.
Hence, one cannot say, for instance:
foo = deleteBy fsteq 42 [(43, "foo"), (44, "bar"), (42, "baz")] where
fsteq a (b,_) = a == b
because Int is not the same as (Int, String).
Is there any good reason for this?
The reason I am asking is that, if there is no good reason for it, I would include deleteBy with the more general type in the Frege port of Data.List I am currently doing. But maybe I am overlooking something?
EDIT: As #hammar pointed out, this applies to other xxxBy functions also.
Generalising the type of deleteBy violates the standard in a very practical way: perfectly valid Haskell programs become invalid, thanks to unresolved overloading.
Here's a demonstration:
class (Num a) => Magic a where
magic :: a -> Bool
sameMagic :: (Magic a, Magic b) => a -> b -> Bool
sameMagic a b = magic a == magic b
test :: (Magic a) => [a]
test = deleteBy sameMagic 42 [1234]
In Haskell, this program is perfectly well-typed; deleteBy's restricted type ensures that the 42 is guaranteed to have the same type as the 1234. With the generalised deleteBy, this is not the case, and so the type of 42 is ambiguous, making the program invalid. (If you want a less contrived example, consider a function which compares two Integral values with toInteger.)
So, perhaps there is no good reason for this restricted type (although if deleteBy is to be generalised, I would prefer hammar's version to your proposal), but generalising it does violate the standard, and it can break valid programs.
I guess it's for symmetry with the other xxxBy functions. However, your type is still needlessly specific. I would prefer this.
deleteBy :: (a -> Bool) -> [a] -> [a]
You could then write your example using partial application:
foo = deleteBy (fsteq 42) [(43, "foo"), (44, "bar"), (42, "baz")] where
fsteq a (b,_) = a == b
Ingo,
in your original question, it seems you're asking why Haskell Report specifies deleteBy like this.
So if there's no strong reason, you could use a different definition in Frege (implying you don't care about Haskell Report conformance).
As Hammar says, it's like the other xxxBy functions: delete uses (==), deleteBy takes a predicate that is like (==): of type (a -> a -> Bool) and assumed to be an equivalence relation. While the type system cannot check if the predicate is really an equivalance relation, it is the function contract. So it's very easy to understand what xxxBy means if you know what xxx means. And maybe it's not the case for deleteBy, but in some cases an implementation might be optimized under the assumption the predicate has the specified properties (equivalence relation or total order, etc).
But in your comment to Hammar's answer, you ask whether the more general implementation would violate the report. Well, if the type is different then it is literally a violation, right? Since programs that shouldn't compile according to the report will be accepted by your compiler. So it gives rise to a portability problem: if your code uses the more general version, then it might not compile on another implementation that conforms to the specification. Besides, it does away with the equivalence relation requirement.
So if you want a more general function, why not simply define another function with a different name? For instance, deleteIf.
(I wanted to comment on Hammar's answer, but I can't so I wrote it here.)

Resources