문제

In the following code all that I ever do with the return value of foo is use its Show interface

foo :: String
foo = "asdf"

main = do
    print foo

Is there a way to modify the type signature offoo to enforce this, forbidding people from treating the string as a list of characters and only letting them access it though the abstract type class interface? I think it might be possible with existential types but I have no idea how.


The reason I want to do this is because in the HDBC database library all the functionality is available as methods of a IConnection type class. I am writing the function that creates the database connection and I want to know if its possible to have its return type reflect the abstract interface instead of returning a concrete Sqlite3 Connection.

Now that I searched a bit I see that there is a ConnWrapper datatype available but I still can't understand how this all fits together. Is returning a ConnWrapper the only way to go?

도움이 되었습니까?

해결책

It's indeed possible with existential types, but it's quite possibly a bad idea.

The way you would do it with an existential type is ConnWrapper, like you said:

data ConnWrapper = forall conn. IConnection conn => ConnWrapper conn

That type is relatively straightforward: It's an IConnection dictionary together with a value of a type compatible with it. If x :: conn, and conn is an instance of IConnection, then ConnWrapper x :: ConnWrapper. Given y :: ConnWrapper, you know nothing about its value's type other than that it's an instance of IConnection. So you can say case y of ConnWrapper z -> disconnect z, but you can't say case y of ConnWrapper z -> z -- there's no Haskell type you can give to that.

(ConnWrapper is also an instance of IConnection directly, and since the class is pretty simple, that means you pretty much never need to pattern-match on ConnWrapper directly. You can just use disconnect y and so on.)

If you were making the API, I'd strongly suggest reconsidering along the lines of the post I linked above, or at least understanding that approach. Many uses of ExistentialTypes in Haskell are actually more complicated than a non-existential approach. For example, you should see why data Foo = forall a. Show a => Foo a is (almost) equivalent to String. It looks like the HDBC may be intended to be used this way, though...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top