Constructor type as return type

In Scala, I can define an Algebraic data type :

scala> sealed trait Maybe[A] defined trait Maybe scala> case class Just[A](x: A) extends Maybe[A] defined class Just scala> case object NothingHere extends Maybe[Nothing] defined object NothingHere 

It is possible to return a function f with the return type Maybe[A] .

 scala> def f[A](x: A): Maybe[A] = Just(x) f: [A](x: A)Maybe[A] 

However, you can also specify that a Just[A] returned.

 scala> def f[A](x: A): Just[A] = Just(x) f: [A](x: A)Just[A] 

Now I will do a similar exercise in Haskell:

 Prelude> data Option a = None | Some a deriving Show Prelude> let fx = Some x :: Option Int Prelude> f 10 Some 10 

But I cannot set the return type of the type constructor.

 Prelude> let fx = Some x :: Some Int <interactive>:10:21: Not in scope: type constructor or class `Some' A data constructor of that name is in scope; did you mean DataKinds? Prelude> let fx = None :: None 

Is the simple difference that Scala Just is a class, i.e. a legal return type? If in Haskell a type constructor cannot be a return type?

+6
source share
2 answers

The difference is how Scala decided to implement ADT. Scala uses case classes that extend the OOP-style trait, so each case is its own type, while Haskell has only a few constructors for the same type. Since they are not separate types, but essentially just separate functions, you cannot distinguish them from the type level. There are extensions that give you the opportunity to make a difference at the level level, but it will not be the same as Scala. And trying to install a system like Haskell into a system like Scala is probably not the best idea.

In short, Scala approximates ADT using an inheritance form, while Haskell only has ADT.

+10
source

bhelkir and leftaroundabout pointed out why you cannot do it exactly in Haskell: there is no concept of subtypes.

But note that using ADT there are often alternatives that can achieve the same effect. In this case, one possible method would be to use the Void type in combination with Either :

 import Data.Void f :: Int -> Either Void Int fx = Right x 

Void is a type that does not have specific values. Therefore, if you see the type Either Void a , this means that since there is no value x :: Void , no one can construct any value of the form Left x :: Either Void a . (An exception is if x is a guaranteed immutable value, but we usually ignore this possibility .)

This means that Either Void a always has the form Right a , therefore, for example, you can write this function:

 -- | Extract the @ a@ from @Either Void a@. extract :: Either Void a -> a extract (Left x) = absurd x extract (Right a) = a 

absurd x works basically like this: since x :: Void means that it can never be a value for x , then absurd :: Void -> a , given its type, is a function that you can never ever call, how it works type system means that it can demand the return of any type what the subscriber expects. See this question for further discussion (although perhaps a bit advanced).

0
source

Source: https://habr.com/ru/post/988459/


All Articles