Could this haskell be shorter?

This is my exercise solution from YAHT:

Exercise 4.6. Write a Tuple data type that can contain one, two, three, or four elements, depending on the constructor (that is, there must be four constructors, one for each number of arguments). In addition, tuple1 functions via tuple4 that take a tuple and return a value at that position or Nothing if the number is in action (i.e. you request tuple4 on a tuple containing only two elements).

When I wrote the first line, I was in awe of simplicity compared to C #

    data Tuplex abcd = Tuple1 a | Tuple2 ab | Tuple3 abc | Tuple4 abcd

    - class Tuplex <a, b, c, d> {
    - Tuplex (a p1) {_p1 = p1; }
    - Tuplex (a p1, b p2) {_p1 = p1; _p2 = p2; }
    - Tuplex (a p1, b p2, c p3) {_p1 = p1; _p2 = p2; _p3 = p3; }
    - Tuplex (a p1, b p2, c p3, d p4) {_p1 = p1; _p2 = p2; _p3 = p3; _p4 = p4; }
    - public Nullable <a> _p1;
    - public Nullable <b> _p2;
    - public Nullable <c> _p3;
    - public Nullable <d> _p4;
    -}

In C #, I can easily access any field, but here I have to write "access functions", right? And the amount of code here upsets me.

Can I have a shorter code here?

    tuple1 ∷ Tuplex abcd β†’ Maybe a
    tuple2 ∷ Tuplex abcd β†’ Maybe b
    tuple3 ∷ Tuplex abcd β†’ Maybe c
    tuple4 ∷ Tuplex abcd β†’ Maybe d
    tuple1 (Tuple1 a) = Just a
    tuple1 (Tuple2 ab) = Just a
    tuple1 (Tuple3 abc) = Just a
    tuple1 (Tuple4 abcd) = Just a
    tuple2 (Tuple1 a) = Nothing
    tuple2 (Tuple2 a b) = Just b
    tuple2 (Tuple3 a b c) = Just b
    tuple2 (Tuple4 a b c d) = Just b
    tuple3 (Tuple1 a) = Nothing
    tuple3 (Tuple2 a b) = Nothing
    tuple3 (Tuple3 a b c) = Just c
    tuple3 (Tuple4 a b c d) = Just c
    tuple4 (Tuple1 a) = Nothing
    tuple4 (Tuple2 a b) = Nothing
    tuple4 (Tuple3 a b c) = Nothing
    tuple4 (Tuple4 a b c d) = Just d

    -- unit tests
    prop_tx1 = tuple1 (Tuple1 4) ≑ Just 4
    prop_tx2 = tuple1 (Tuple2 4 'q') ≑ Just 4
    prop_tx3 = tuple2 (Tuple1 4) ≑ (Nothing ∷ Maybe Char)
    prop_tx4 = tuple2 (Tuple2 4 'q') ≑ Just 'q'

+5
4

: .

unTuplex f1 f2 f3 f4 t = case t of
    Tuple1 a       -> f1 a
    Tuple2 a b     -> f2 a b
    Tuple3 a b c   -> f3 a b c
    Tuple4 a b c d -> f4 a b c d

tuple1 = unTuplex (\a -> Just a ) (\a _ -> Just a ) (\a _ _ -> Just a ) (\a _ _ _ -> Just a)
tuple2 = unTuplex (\_ -> Nothing) (\_ b -> Just b ) (\_ b _ -> Just b ) (\_ b _ _ -> Just b)
tuple3 = unTuplex (\_ -> Nothing) (\_ _ -> Nothing) (\_ _ c -> Just c ) (\_ _ c _ -> Just c)
tuple4 = unTuplex (\_ -> Nothing) (\_ _ -> Nothing) (\_ _ _ -> Nothing) (\_ _ _ d -> Just d)

:

{-# LANGUAGE NoMonomorphismRestriction #-}
data DONE = DONE -- could just use (), but this is a pretty descriptive name
type Tuplex a b c d = Maybe (a, Maybe (b, Maybe (c, Maybe (d, DONE))))

tuple1 x = x >>= return . fst -- or tuple1 = fmap fst
tuple2 x = x >>= tuple1 . snd
tuple3 x = x >>= tuple2 . snd
tuple4 x = x >>= tuple3 . snd

tuple1 ( ) Tuplex a b c d -> Maybe a, tuple4, ( , ) Tuplex a b c d -> Maybe d.

edit:... .

import Control.Monad

decrement :: Tuplex a b c d -> Maybe (Tuplex b c d t)
decrement (Tuple1 a) = Nothing
decrement (Tuple2 a b) = Just (Tuple1 b)
decrement (Tuple3 a b c) = Just (Tuple2 b c)
decrement (Tuple4 a b c d) = Just (Tuple3 b c d)

zero :: Tuplex a b c d -> a
zero (Tuple1 a) = a
zero (Tuple2 a b) = a
zero (Tuple3 a b c) = a
zero (Tuple4 a b c d) = a

tuple1 = Just . zero
tuple2 = decrement >=> tuple1
tuple3 = decrement >=> tuple2
tuple4 = decrement >=> tuple3
+7

, :

data Tuplex a b c d = Tuple1 a | Tuple2 a b | Tuple3 a b c | Tuple4 a b c d

toMaybes (Tuple1 p)       = (Just p, Nothing, Nothing, Nothing)
toMaybes (Tuple2 p q)     = (Just p, Just  q, Nothing, Nothing)
toMaybes (Tuple3 p q r)   = (Just p, Just  q, Just  r, Nothing)
toMaybes (Tuple4 p q r s) = (Just p, Just  q, Just  r, Just  s)

tuple1 t = p where (p,_,_,_) = toMaybes t 
tuple2 t = q where (_,q,_,_) = toMaybes t 
tuple3 t = r where (_,_,r,_) = toMaybes t 
tuple4 t = s where (_,_,_,s) = toMaybes t
+7

!

data Tuplex a b c d = Tuple1 { tuple1 :: a }
                    | Tuple2 { tuple1 :: a
                             , tuple2 :: b }
                    | Tuple3 { tuple1 :: a
                             , tuple2 :: b
                             , tuple3 :: c }
                    | Tuple4 { tuple1 :: a
                             , tuple2 :: b
                             , tuple3 :: c
                             , tuple4 :: d }

:

tuple1 :: Tuplex a b c d -> a
tuple2 :: Tuplex a b c d -> b
-- etc

, Haskell - , , , RecordWildCard, ,

function (Tuples3 {..}) =
-- now you have variables tuple1 :: a, tuple2 :: b, etc.

( - , tupA, tupB, tupC, tupD)

+1
import Safe (atMay) -- from the 'safe' package

toList (Tuple1 a) = [a]
toList (Tuple2 a b) = [a, b]
toList (Tuple3 a b c) = [a, b, c]
toList (Tuple4 a b c d) = [a, b, c, d]

tuple n t = atMay (toList t) n

[tuple1, tuple2, tuple3, tuple4] = map tuple [1..4]

: , , . .

+1

All Articles