niedziela, lutego 22, 2009

Instancja klasy Show dla funkcji

Wbrew pozorom łatwo napisać taką instancję. Nie będzie ona spełniała warunku
> (read . show) == id
ale może być użyteczna. Można ją znaleźć w przypadku GHC 6.10 w module Text.Show.Functions. Wygląda ona tak:

instance Show (a -> b) where
     showsPrec _ _ = showString "<function>"

Dzisiaj wpadłem na nieco pożyteczniejszą formę. Niestety, wszystko ma swoją cenę - zadziała ona tylko dla funkcji których argumenty są elementami klasy Typeable.

instance (Typeable a, Typeable b) => Show (a -> b) where
     show _ = "<function: " ++ show (typeOf (undefined :: a)) ++ " -> " ++ show (typeOf (undefined :: b)) ++ ">"

Przykładowe działanie:
*Main> print print
Loading package syb ... linking ... done.
<function: () -> IO ()>
*Main> :set -Wall
*Main> print print

<interactive>:1:6:
     Warning: Defaulting the following constraint(s) to type `()'
         `Show a' arising from a use of `print' at <interactive>:1:6-10
         `Typeable a' arising from a use of `print' at <interactive>:1:0-10
     In the first argument of `print', namely `print'
     In a stmt of a 'do' expression: it <- print print
<function: () -> IO ()>
*Main> print putStrLn
<function: [Char] -> IO ()>
*Main> print id

<interactive>:1:0:
     Ambiguous type variable `a' in the constraint:
         `Typeable a' arising from a use of `print' at <interactive>:1:0-7
     Probable fix: add a type signature that fixes these type variable(s)
*Main> print (id :: Int -> Int)
<function: Int -> Int>
*Main> print (undefined :: Int -> Int -> Int)
<function: Int -> Int -> Int>

środa, lutego 11, 2009

Rozmowa o pracę

Stanowisko: informatyk / programista.

Tak, wiem, że to dość ogólne określenie. Nie mniej jednak ktokolwiek przychodzi na rozmowę kwalifikacyjną i wpisuje w CV znajomość C++ powinien oczekiwać, że poprosi się go o napisanie jakiegoś programu. Prostego. Na przykład liczącego n-ty element ciągu Fibonacciego. Prosty, banalny wręcz program.

Nie oczekuję wersji jedno-dwulinijkowej w Haskellu:

fib n = fibs !! n
fibs = 0 : 1 : (zipWith (+) fibs (tail fibs)) :: [Integer]

Nie oczekuję też rozwiązania powiązanego równania rekurencyjnego i napisania tej funkcji tak, by działała w czasie (praktycznie) stałym (zostawiam to zadanie czytelnikom).

Oczekuję prostej definicji w C. Ba, może być nawet taka, która ma złożoność wykładniczą!

int fib(int n)
{
    if (n==0) return 0;
    if (n==1) return 1;
    return fib(n-1) + fib(n-2);
}

Jak widać powyżej nie ma nawet sprawdzenia czy argument jest ujemny czy też nie. Pisanie powyższych kilku linijek przez pół godziny (i to bez powodzenia...) to strata czasu - obu stron.

wtorek, lutego 03, 2009

Przetestuj, jak TWOJA przeglądarka renderuje UTF-8

A tak na prawdę to tylko krótki programik do wypisania wszystkich znaków rozpoznawanych jako litery w kodowaniu UTF-8.

> module Main where
> import Prelude hiding ( writeFile )
> import System.IO.UTF8 ( writeFile )-- package 'utf8-string' on Hackage
> import Data.List.Split ( splitEvery ) -- package 'split' on Hackage
> import Data.Char ( isAlpha )
> import Data.List ( intercalate )
> main = writeFile "out.html" (header ++ chars ++ footer)
>         where
>         header = "<HTML><HEAD><META HTTP-EQUIV=\"Content-type\" CONTENT=\"text/html; charset=utf-8\"></HEAD><BODY>"
>         chars = intercalate "\n<br>" . splitEvery 40 . filter isAlpha $ [ minBound .. maxBound ]
>         footer = "</BODY></HTML>"

Przykładowy wynik działania znajduje się tutaj. Treść tego posta jest jednocześnie kodem programu - wystarczy zaznaczyć całość, skopiować i zapisać z rozszerzeniem .lhs. Zrozumie go GHC, choć do uruchomienia będą potrzebne dodatkowe pakiety (patrz kod programu).

niedziela, lutego 01, 2009

Evil macro magic

Ostatnio w zobaczyłem ciekawy fragment kodu (C++):

#include "settings.hpp"
/* evil macro magic */
#undef _SETTINGS_HPP
#define extern
#include "settings.hpp"
#undef extern

Ciężko mi skomentować tak ciężkie nadużycie - które z drugiej strony jest genialne :-) Wyjaśnienie: powyższe linijki sprawiają, że wszystkie deklaracje "extern" zmiennych w "settings.hpp" stają się zwykłymi deklaracjami. Może to prowadzić do bardzo nieprzyjemnych błędów, ale zapewne czasami jest to użyteczne.