What is returning with printf?

I am studying Haskell, and these are my first steps in trying to understand the syntax. It’s very hard for me, and, unfortunately, the link to the language is not very useful.

I tried to do :type (line_length 1 2 3 4) and I have a red link to printf However, it uses characters with an undefined value instead of words. So, I got stuck and asked for help.

Put it simply: what am I writing instead ??? .

 line_length :: Integer -> Integer -> Integer -> Integer -> ??? line_length ax ay bx by = printf ("The length of the line between the points" ++ "(%d,%d) and (%d,%d) is %.5f\n") ax ay bx by ((((fromIntegral (ax - bx)) ** 2.0) + ((fromIntegral (ay - by))) ** 2.0) ** 0.5) 
+4
source share
2 answers

The overloaded return type printf :: PrintfType r => String -> r may be a bit confusing, but it helps to look at the available PrintfType instances:

  • First we have this instance:

     instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) 

    This one is used to allow printf to accept a variable number of arguments. This makes sense because of currying, but you probably won't think of it as a β€œtrue” function type return. For more information on how this works, see How printf works in Haskell? .

  • Then we have this instance,

     instance PrintfType (IO a) 

    This means that we can use it as an IO action. Like print , this will output the result to standard output. The result of the action is undefined , so you should just ignore it. one

     > printf "Foo %d\n" 42 :: IO () Foo 42 > it *** Exception: Prelude.undefined 
  • And finally

     instance IsChar c => PrintfType [c] 

    The type class here basically allows you to make it compatible with Haskell 98. Since Char is the only instance of IsChar , you can think of it as

     instance PrintfType String 

    but this will require an extension of the GHC-specific extension of FlexibleInstances .

    What this instance means is that you can also just return a String without printing it, similar to sprintf in C.

     > printf "Foo %d\n" 42 :: String "Foo 42\n" 

So, depending on whether you want to print the result or just return it, you can replace ??? on IO () or String in your example.

However, there is another problem with your code that the compiler cannot determine which type you need the last argument to, so you need help with the type annotation:

 line_length :: Integer -> Integer -> Integer -> Integer -> String line_length ax ay bx by = printf ("The length of the line between the points" ++ "(%d,%d) and (%d,%d) is %.5f\n") ax ay bx by ((((fromIntegral (ax - bx)) ** 2.0) + ((fromIntegral (ay - by))) ** 2.0) ** 0.5 :: Double) 

1 This is to avoid extensions. With extensions, we could write instance PrintfType (IO ()) , and the result would be () .

+12
source

When I get hung up on type signatures, I let Haskell work hard for me. That is, I

  • write a definition without a type signature
  • upload it to ghci
  • interactively check the type that Haskell gave him
  • copy this signature down (make sure it was what I intended) in the source file
+1
source

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


All Articles