Skip to content

stepcut/safe-length

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 

Are you sick and tired of accidentally applying length to a tuple and getting back 1 instead of a compilation error? Does it make you feel like giving up on Haskell?

At last, there is a solution -- safeLength. For zero easy payments of 0 dollars and 00 cents, you can get the type safety you long for!

Before, if you accidentally wrote:

main :: IO ()
main = print $ length ('a', 'b')

you would get:

*Main> main
1

But with the new and improved safeLength you can rest easy. If you write:

main :: IO ()
main = print $ safeLength (Proxy :: Proxy [Char]) ('a', 'b')

You now get the glorious error:

*Main> :load example/Tuple.hs
[1 of 2] Compiling Data.Length      ( src/Data/Length.hs, interpreted )
[2 of 2] Compiling Main             ( example/Tuple.hs, interpreted )

example/Tuple.hs:7:51:
    Couldn't match type ‘(,) Char’ with ‘[]’
    Expected type: [Char]
      Actual type: (Char, Char)
    In the second argument of ‘safeLength’, namely ‘('a', 'b')’
    In the second argument of ‘($)’, namely
      ‘safeLength (Proxy :: Proxy [Char]) ('a', 'b')’
    In the expression:
      print $ safeLength (Proxy :: Proxy [Char]) ('a', 'b')
Failed, modules loaded: Data.Length.

"But wait!", you say. "I want to take the length of a tuple." No problem! safeLength can do that too!

main :: IO ()
main = print $ safeLength (Proxy :: Proxy (Char, Char)) ('a', 'b')

As desired, we get 1:

*Main> main
1

But that's not all! What if you have nested lists and you accidentally take the length of the wrong list. For example, what if you want the length of the outer list, but you accidentally write:

import GHC.OldList as OldList

main :: IO ()
main = print $ OldList.length (head [['a','b','c']])

Oh the horror! It compiles and we get:

*Main> main
3

And that is even using the old monomorphic, length :: [a] -> Int!!

But with safeLength all is well! If we accidentally write:

main :: IO ()
main = print $ safeLength (Proxy :: Proxy [[Char]]) (head [['a', 'b', 'c']])

We get not 1, not 2, but 3 type errors

*Main> :load example/NestedList.hs
[1 of 2] Compiling Data.Length      ( src/Data/Length.hs, interpreted )
[2 of 2] Compiling Main             ( example/NestedList.hs, interpreted )

example/NestedList.hs:7:61:
    Couldn't match expected type ‘[Char]’ with actual type ‘Char’
    In the expression: 'a'
    In the expression: ['a', 'b', 'c']
    In the first argument of ‘head’, namely ‘[['a', 'b', 'c']]’

example/NestedList.hs:7:66:
    Couldn't match expected type ‘[Char]’ with actual type ‘Char’
    In the expression: 'b'
    In the expression: ['a', 'b', 'c']
    In the first argument of ‘head’, namely ‘[['a', 'b', 'c']]’

example/NestedList.hs:7:71:
    Couldn't match expected type ‘[Char]’ with actual type ‘Char’
    In the expression: 'c'
    In the expression: ['a', 'b', 'c']
    In the first argument of ‘head’, namely ‘[['a', 'b', 'c']]’
Failed, modules loaded: Data.Length.

That's right! 3 type errors for the low, low price of $0.00.

Act now and we'll throw in these unit tests at no additional cost! Don't delay! Hackage servers are standing by!

About

Tired of accidentally calling length on tuples? Relief at last!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published