|
5 minute guide to Haskell: Any time you see a '::', it means 'the thing on the left hand side has the type on the right hand side'. As such, you should parse this line as 'there is a function jonk that has a type '(a -> b) -> ((a -> Int) -> Int) -> ((b -> Int) -> Int)'. A simple type in Haskell is `Int -> Bool`. This means a function that takes a value of type Int and return a value of type Bool. Now `Int -> (Int -> Bool)`, means 'a function that takes a value of type Int and returns a function that takes a value of type Int and returns a value of type Bool'. And because currying, this can be also read as 'a function that takes a value of type Int, then a value of type Int, and returns a value of type Bool'. As in, if you first call the function with Int, you'll be getting an `Int -> Bool` in return. Then you call it again with Int, and then you get a Bool. Because of how we define precedence of things, this signature can also be written as `Int -> Int -> Bool`, which makes it a bit more readable. However, if you really want to grok Haskell you need to grok this equivalency early on. Compare this to `(Int -> Int) -> Bool`. This means 'a function that takes a function that takes a type Int and returns a type Int, and returns a type Bool'. By this point you should see that the type is more readable than my human language descriptions. One last thing you're missing is the types 'a' and 'b'. You'll notice that these start with a small letter, and that's because they are generic types. It means that in practice this function can be called with whatever type instead of 'a' and 'b' in the declaration, it's just that it must be the same type for all cases of 'a' and 'b'. For a simple example, let's look at a function that takes two Ints, a Bool, and returns the first Int if the boolean is true, otherwise the second. The type signature for this in Haskell would be `foo :: Int -> Int -> Bool -> Int`. However, the function doesn't really care that these are Ints - they might as well be any values. As such, we can define the function signature as `foo :: a -> a -> Bool -> a`. This is is naturally similar to generic in C++, Typescript or Rust. Armed with this knowledge (albeit maybe explained a bit better - see Learn You A Haskell!) you should be able to read this complex type signature now. |