2012-02-22 5 views
4

Я изучаю Haskell, и это мои первые шаги в попытке понять синтаксис. У меня очень тяжелое время, и, к сожалению, ссылка на язык не очень полезна.Что возвращается с printf?

Я попытался сделать :type (line_length 1 2 3 4), и у меня есть красный reference on printf Однако он использует символы с неопределенным значением вместо слов. Итак, я застрял и попросил о помощи.

Простой: что я пишу вместо ???.

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) 
+6

Printf не является хорошим началом, если вы хотите изучить Haskell. Какой тип вы хотите 'line_length' для возврата? – augustss

+2

BTW, '(^ 2)' лучше, чем '(** 2)', а 'sqrt' лучше, чем' (** 0.5) '. – augustss

+1

Ссылка на язык, конечно, не очень хороший источник обучения для понимания синтаксиса. Вы не пробовали одну из простых книг/учебников, таких как [LYAH] (http://learnyouahaskell.com/), [RWH] (http://book.realworldhaskell.org/) или [YAHT] (http: //www.cs.utah.edu/~hal/htut/)? – leftaroundabout

ответ

12

Перегруженный тип возврата printf :: PrintfType r => String -> r может быть немного запутанным, но он помогает посмотреть на PrintfType экземпляров, которые доступны:

  1. Во-первых, у нас есть этот экземпляр:

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

    Это один используется, чтобы позволить printf принимать переменное число аргументов. Это имеет смысл из-за currying, но вы, вероятно, не будете думать об этом как о «истинном» возврате типа функции. Для получения дополнительной информации о том, как это работает, см. How does printf work in Haskell?.

  2. Тогда мы имеем этот экземпляр,

    instance PrintfType (IO a) 
    

    Это означает, что мы можем использовать его в качестве IO действия. Подобно print, это приведет к выводу результата на стандартный вывод. Результатом действия является undefined, поэтому вы должны просто игнорировать его.

    > printf "Foo %d\n" 42 :: IO() 
    Foo 42 
    > it 
    *** Exception: Prelude.undefined 
    
  3. И, наконец,

    instance IsChar c => PrintfType [c] 
    

    тип класса здесь, в основном, чтобы позволить этому быть Haskell 98 совместимыми. Так как единственный экземпляр IsChar является Char, вы можете думать об этом как

    instance PrintfType String 
    

    , но для этого потребуется GHC-специфичное расширение FlexibleInstances.

    Этот пример означает, что вы также можете просто вернуть String без его печати, аналогично sprintf в C.

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

Поэтому в зависимости от того, хотите ли вы, чтобы распечатать результат или просто вернуть его, вы можете заменить ??? либо IO() или String в вашем примере.

Однако, есть еще одна проблема с вашим кодом в том, что компилятор не может определить, какой тип вы хотели последний аргумент, чтобы быть, так что вы должны помочь ему с аннотации типа:

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) 

Это делается, чтобы избежать расширений. С расширениями мы могли бы написать instance PrintfType (IO()), и результат будет ().

1

Когда я застрял под подписью типа, я позволил Haskell усердно работать для меня. То есть, я

  • написать определение без сигнатуры типа
  • загрузить его в ghci
  • интерактивно проверить тип, Haskell дал ему
  • скопировать эту подпись вниз (убедитесь, что это то, что я предназначенный) в исходном файле
+5

В этом случае это будет довольно неинформативно. – augustss

Смежные вопросы