Jasne, z odrobiną klasy rodzaju "magii":
{-# LANGUAGE DataKinds, KindSignatures, UndecidableInstances #-}
data Nat = Z | S Nat
data SNat (n :: Nat) where
SZ :: SNat Z
SS :: SNat n -> SNat (S n)
class ApplyNth (n :: Nat) arg fn fn' | n arg fn -> fn', n fn -> arg where
applyNth :: SNat n -> arg -> fn -> fn'
instance ApplyNth Z a (a -> b) b where
applyNth SZ a f = f a
instance ApplyNth n arg' fn fn' => ApplyNth (S n) arg' (arg0 -> fn) (arg0 -> fn') where
applyNth (SS n) a f = \a0 -> applyNth n a (f a0)
ogólnego typu dla applyNth
mówi, zajmuje indeks (liczbę naturalną - zakodowany w typie), argument, A funkcja i zwraca funkcję.
Zwróć uwagę na dwie zależności funkcjonalne. Pierwsza mówi, że biorąc pod uwagę indeks, argument i funkcję wejściową, znany jest typ funkcji wyjściowej. To jest oczywiste. Drugi mówi, że biorąc pod uwagę indeks i funkcję wejściową, ApplyNth
jest w stanie zajrzeć do funkcji i dowiedzieć się, jakiego argumentu potrzebuje!
Funkcja ta gra całkiem dobrze z typu wnioskowania:
>:t \x -> applyNth (SS SZ) x (^)
\x -> applyNth (SS SZ) x (^)
:: (Num fn', Integral b) => b -> fn' -> fn'
>:t applyNth (SS SZ) 0 (^)
applyNth (SS SZ) 0 (^) :: Num fn' => fn' -> fn'
>:t applyNth (SS SZ) (0 :: Integer) (^)
applyNth (SS SZ) (0 :: Integer) (^) :: Num fn' => fn' -> fn'
>:t applyNth (SS SZ) ('a' :: Char) (^)
<interactive>:1:32: Warning:
Could not deduce (Integral Char) arising from a use of `^'
...
applyNth (SS SZ) ('a' :: Char) (^) :: Num fn' => fn' -> fn'
>let squared = applyNth (SS SZ) 2 (^)
>:t squared
squared :: Num fn' => fn' -> fn'
>squared 3
9
>squared 100
10000
>let f a b c d e = mapM_ putStrLn
[ show n ++ ": " ++ x
| (n,x) <- zip [0..]
[show a, show b, show c, show d, show e] ]
>applyNth SZ 'q' $
applyNth (SS $ SZ) [1,8,42] $
applyNth SZ (True, 10) $
applyNth (SS $ SS $ SS SZ) "abcd" $
applyNth (SS $ SS $ SS SZ) pi $
f
0: (True,10)
1: 'q'
2: [1,8,42]
3: 3.141592653589793
4: "abcd"
Można również zdefiniować go w postaci operatora:
infixl 9 =:
(=:) :: ApplyNth n arg fn fn' => SNat n -> arg -> fn -> fn'
(=:) = applyNth
r =
SZ =: 'q' $
SS SZ =: [1,8,42] $
SZ =: (True, 10) $
(SS $ SS $ SS SZ) =: "abcd" $
(SS $ SS $ SS SZ) =: pi $
f
Wyszukiwanie "funkcji variadycznych w Haskell" – Bergi
[W szczególności jest] (http://okmij.org/ftp/Haskell/polyvariadic.html#polyvar-fn) –
Sądzę, że mogłem [coś powiedzieć o tym problemie, dawno temu] (http://strictlypositive.org/ faking.ps.gz). Niektórzy wciąż mogą zaprzeczać, ale Haskell w rzeczywistości był naprawdę dość zależny od pisania naprawdę przez jakiś czas. – pigworker