문제

We can define function f and g like this:

f :: [a] -> [a] -> [a]
f = (++)

g :: [a] -> [a] -> [a]
g = zipWith (+)

Both f and g take two lists as parameters and return a new list, but they are different: f returns a longer list whose length is the sum of the inputs', meanwhile g processes lists with the same length. How to figure this out to Haskell?

도움이 되었습니까?

해결책

What you want is to encode the length of lists into the type system. In other words, encode natural numbers in the type system and operations on them. This is possible, although it involves some type trickery. There are libraries to achieve this, one of them tagged-list. TaggedList is tagged with its length as a type-level natural number. Then the types of your functions would look like

import Data.List.Tagged as T
import TypeLevel.NaturalNumber.Operations (Plus)

f :: TaggedList n a -> TaggedList m a -> TaggedList (Plus n m) a
f = T.append

g :: (Num a) => TaggedList n a -> TaggedList n a -> TaggedList n a
g x = T.zipf (T.map (+) x) -- apparently the Tagged library lacks zipWith
                           -- so we implement it ourselves

which gives clear distinction of what happens with the length of the lists.

See also Type arithmetic.

다른 팁

From what I gather, you want your g to check that the lists are the same length first before performing the operation. That's relatively easy:

-- Correct type signature as @chris mentioned
g :: Num a => [a] -> [a] -> [a]
g xs ys = if length xs == length ys then zipWith (+) xs ys else error "Incompatible lists"

However, this is a really bad way to throw errors, you'd be better off using the Maybe monad:

g :: Num a => [a] -> [a] -> Maybe [a]
g xs ys = if length xs == length ys then Just $ zipWith (+) xs ys else Nothing
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top